Чересчур умный указатель
От: Аноним  
Дата: 19.01.07 13:08
Оценка:
В коде приведенном ниже программа почему-то падает в случае (2).
Просто фантастика, не могу понять почему... Уже день за отладчиком провел...

Помогите, пожалуйста...



// TestErr.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

namespace Gr
{

struct Error
{
    virtual const char * type() = 0;
    virtual const char * what() = 0;
};

class RuntimeError
    : public Error
{
public:
    RuntimeError( const string& sErr )
        : mErr( sErr )
    {}

private:
    const char * type()
    { return "RUNTIME ERROR"; }
    
    const char * what()
    { return mErr.c_str(); }

    string mErr;
};

template<typename T>
class weak_ptr
{
public:
    weak_ptr( T * p = 0 )
        : mp( p )
    {}

    template<typename U>
    weak_ptr( const weak_ptr<U>& wp )
    {
        mp = wp.mp;
        wp.reset();
    }

    template<typename U>
    weak_ptr( U * p )
        : mp( p )
    {
    }

    ~weak_ptr()
    { reset(); }

    void reset( T * p = 0 )
    {
        if( mp != 0 )
            delete mp;

        mp = p;
    }

    operator bool () const
    {
        return mp != 0;
    }

    T * operator -> () const
    {
        assert( mp != 0 );
        return mp;
    }

private:
    T * mp;
}; // class weak_ptr


class ErrStorage
{
public:
    ErrStorage( Error * p = 0 )
        : mp( p )
    {}

    Error * operator -> () const
    { return mp; }

    operator bool () const
    { return mp != 0; }
private:
    Error * mp;
};

//typedef ErrStorage ErrorPtr; // (1)
typedef weak_ptr<Error> ErrorPtr; // (2)
//typedef Error * ErrorPtr; // (3)

ErrorPtr someOperation( int arg1, int arg2 )
{
    if( arg1 > arg2 )
        return new RuntimeError("error in arguments");

    return 0;
}

}


int main(int argc, char * argv[])
{
    cout << "IN MAIN" << endl;

    Gr::ErrorPtr e;

    if( e = Gr::someOperation(15, 10) )
    {
        cout << " (" << e->type() << "): " << e->what() << endl;
    }

    getchar();
    return 0;
}
Re: Чересчур умный указатель
От: Smal Россия  
Дата: 19.01.07 13:20
Оценка:
Здравствуйте, Аноним, Вы писали:

А>В коде приведенном ниже программа почему-то падает в случае (2).

А>Просто фантастика, не могу понять почему... Уже день за отладчиком провел...

А>Помогите, пожалуйста...



А>

А>// TestErr.cpp : Defines the entry point for the console application.
А>//

А>#include <iostream>
А>#include <string>
А>#include <cassert>

А>using namespace std;

А>namespace Gr
А>{

А>struct Error
А>{
А>    virtual const char * type() = 0;
А>    virtual const char * what() = 0;
А>};

А>class RuntimeError
А>    : public Error
А>{
А>public:
А>    RuntimeError( const string& sErr )
А>        : mErr( sErr )
А>    {}

А>private:
А>    const char * type()
А>    { return "RUNTIME ERROR"; }
    
А>    const char * what()
А>    { return mErr.c_str(); }

А>    string mErr;
А>};

А>template<typename T>
А>class weak_ptr
А>{
А>public:
А>    weak_ptr( T * p = 0 )
А>        : mp( p )
А>    {}

А>    template<typename U>
А>    weak_ptr( const weak_ptr<U>& wp )
А>    {
А>        mp = wp.mp;
А>        wp.reset();
А>    }

А>    template<typename U>
А>    weak_ptr( U * p )
А>        : mp( p )
А>    {
А>    }

А>    ~weak_ptr()
А>    { reset(); }

А>    void reset( T * p = 0 )
А>    {
А>        if( mp != 0 )
А>            delete mp;

А>        mp = p;
А>    }

А>    operator bool () const
А>    {
А>        return mp != 0;
А>    }

А>    T * operator -> () const
А>    {
А>        assert( mp != 0 );
А>        return mp;
А>    }

А>private:
А>    T * mp;
А>}; // class weak_ptr


А>class ErrStorage
А>{
А>public:
А>    ErrStorage( Error * p = 0 )
А>        : mp( p )
А>    {}

А>    Error * operator -> () const
А>    { return mp; }

А>    operator bool () const
А>    { return mp != 0; }
А>private:
А>    Error * mp;
А>};

А>//typedef ErrStorage ErrorPtr; // (1)
А>typedef weak_ptr<Error> ErrorPtr; // (2)
А>//typedef Error * ErrorPtr; // (3)

А>ErrorPtr someOperation( int arg1, int arg2 )
А>{
А>    if( arg1 > arg2 )
А>        return new RuntimeError("error in arguments");

А>    return 0;
А>}

А>}


А>int main(int argc, char * argv[])
А>{
А>    cout << "IN MAIN" << endl;

А>    Gr::ErrorPtr e;

А>    if( e = Gr::someOperation(15, 10) )
А>    {
А>        cout << " (" << e->type() << "): " << e->what() << endl;
А>    }

А>    getchar();
А>    return 0;
А>}

А>


А оператор = кто будет переопределять?
К тому же, этот код компилиться не будет. Метод reset не константный.

    template<typename U>
    weak_ptr( const weak_ptr<U>& wp )
    {
        mp = wp.mp;
        wp.reset();
    }

Используй std::auto_ptr.
С уважением, Александр
Re[2]: Чересчур умный указатель
От: Аноним  
Дата: 19.01.07 13:25
Оценка:
Здравствуйте, Smal, Вы писали:

S>...


S>А оператор = кто будет переопределять?


Есть конструктор копирования. Оператор = не нужен в данном случае.

S>К тому же, этот код компилиться не будет. Метод reset не константный.


Приведенный код БУДЕТ компилироваться, пока этот шаблонный метод не будет использован (т.е. по всем правилам метод инстанцируется только в случае его использования).
Re[3]: Чересчур умный указатель
От: StevenIvanov США  
Дата: 19.01.07 13:48
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приведенный код БУДЕТ компилироваться, пока этот шаблонный метод не будет использован (т.е. по всем правилам метод инстанцируется только в случае его использования).


Да, сорри, я имел в виду, что const в шаблонном методе конечно же был лишний, но тем не менее код скомпилируется
Re[3]: Чересчур умный указатель
От: Smal Россия  
Дата: 19.01.07 13:49
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Smal, Вы писали:


S>>...


S>>А оператор = кто будет переопределять?


А>Есть конструктор копирования. Оператор = не нужен в данном случае.


S>>К тому же, этот код компилиться не будет. Метод reset не константный.


А>Приведенный код БУДЕТ компилироваться, пока этот шаблонный метод не будет использован (т.е. по всем правилам метод инстанцируется только в случае его использования).


Списибо, это я знаю. Только смысл писать код, который инстанцироваться не будет?
Проблема в том, что оператор = должен иметь такую же сигнатуру, т.е. принимать параметр
по константной ссылке (иначе нельзя будет использовать возвращаемое значение из функции).
Это возможно при использовании микрософтовских фич (VS c включенными фичами позволяет передавать
временный объект по не константной ссылке), но не в рамках стандарта. Для того, что бы решить
эту проблему придумали auto_ptr_ref.
С уважением, Александр
Re[3]: Чересчур умный указатель
От: Lorenzo_LAMAS  
Дата: 19.01.07 13:50
Оценка:
А>Приведенный код БУДЕТ компилироваться, пока этот шаблонный метод не будет использован (т.е. по всем правилам метод инстанцируется только в случае его использования).

а что у тебя происходит в

e = Gr::someOperation(15, 10)


ты представляешь?
Of course, the code must be complete enough to compile and link.
Re[3]: Чересчур умный указатель
От: Smal Россия  
Дата: 19.01.07 13:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Smal, Вы писали:


S>>...


S>>А оператор = кто будет переопределять?


А>Есть конструктор копирования. Оператор = не нужен в данном случае.

Не правда.

T a; // конструктор по умолчанию
T b = a; // конструктор копирования
a = b;   // оператор =


В твоем случае вызывается именно оператор =.
С уважением, Александр
Re[4]: Чересчур умный указатель
От: Lorenzo_LAMAS  
Дата: 19.01.07 13:56
Оценка: 2 (1) +1
кстати, на всякий случай:

>Есть конструктор копирования. Оператор = не нужен в данном случае.


В приведенном тобою коде его нет.

Вот это вот:

template<typename U>
    weak_ptr( const weak_ptr<U>& wp )
    {
        mp = wp.mp;
        wp.reset();
    }


не конструктор копирования. Компилятор неявно сгенерит конструктор копирования, что-то вроде:

weak_ptr(const weak_ptr<T> &); //тот же T, которым ты параметризовал свой класс, он будет просто почленно копировать и reset вызван не будет (да и зачем он тебе, если это weak_ptr????).

Вообще, глядя на твой код трудно понять, что ты хочешь. Хинт в e = Gr::someOperation(15, 10) будет временный объект, деструктор которого освободит память, к которой ты обратишься потом в e->type().
Of course, the code must be complete enough to compile and link.
Re[4]: Чересчур умный указатель
От: StevenIvanov США  
Дата: 19.01.07 14:03
Оценка:
Здравствуйте, Smal, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, Smal, Вы писали:


S>>>...


S>>>А оператор = кто будет переопределять?


А>>Есть конструктор копирования. Оператор = не нужен в данном случае.

S>Не правда.

S>
S>T a; // конструктор по умолчанию
S>T b = a; // конструктор копирования
S>a = b;   // оператор =
S>


S>В твоем случае вызывается именно оператор =.


OK. (кстати, я знаю про auto_ptr — но мне нужно разобраться в частном weak_ptr)

видоизменяем код Gr::weak_ptr так:

(добавили operator =, удалили const в конструкторе копирования)
template<typename T>
class weak_ptr
{
public:
    weak_ptr( T * p = 0 )
        : mp( p )
    {}

    template<typename U>
    weak_ptr( weak_ptr<U>& wp )
    {
        mp = wp.mp;
        wp.reset();
    }

    template<typename U>
    weak_ptr( U * p )
        : mp( p )
    {
    }

    ~weak_ptr()
    { reset(); }

    void reset( T * p = 0 )
    {
        if( mp != 0 )
            delete mp;

        mp = p;
    }

    operator bool () const
    {
        return mp != 0;
    }

    template<typename U>
    weak_ptr operator = ( const weak_ptr<U>& rhs )
    {
        mp = rhs.mp;
        rhs.reset();

        return *this;
    }

    T * operator -> () const
    {
        assert( mp != 0 );
        return mp;
    }

private:
    T * mp;
}; // class weak_ptr



Почему баг не исчезает?
Re[5]: Чересчур умный указатель
От: StevenIvanov США  
Дата: 19.01.07 14:05
Оценка:
L_L>Вообще, глядя на твой код трудно понять, что ты хочешь. Хинт в e = Gr::someOperation(15, 10) будет временный объект, деструктор которого освободит память, к которой ты обратишься потом в e->type().

Спасибо.

И в правду заблудился в 3х соснах.
Re[5]: Чересчур умный указатель
От: Smal Россия  
Дата: 19.01.07 14:32
Оценка:
Здравствуйте, StevenIvanov, Вы писали:

SI>Почему баг не исчезает?

А теперь вспомним, что конструктор копирования и оператор = для
того же класса не должен быть шаблоном. %)
У тебя operator= даже не инстанциируется, т.к. используется сгенеренный компилятором.
С уважением, Александр
Re[6]: Чересчур умный указатель
От: MrSmit Россия  
Дата: 19.01.07 14:37
Оценка:
Кроме шаблонности он еще и написан не совсем правильно — вызывает reset() а тот соответственно delete...

S>А теперь вспомним, что конструктор копирования и оператор = для

S>того же класса не должен быть шаблоном. %)
S>У тебя operator= даже не инстанциируется, т.к. используется сгенеренный компилятором.
Re[6]: Чересчур умный указатель
От: StevenIvanov США  
Дата: 19.01.07 15:01
Оценка:
Здравствуйте, Smal, Вы писали:

S>...


Спасибо за советы, ты безусловно прав (видимо пятница плохо повлияла на меня — мысли только о выходных),
тема закрыта
Автор: Lorenzo_LAMAS
Дата: 19.01.07
.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.