передать право собственности на объект с размещением нового - PullRequest
0 голосов
/ 17 мая 2011

У меня есть проект Visual Studio 2008 C ++ с классом, который управляет ресурсом, который не может быть скопирован.Я реализовал семантику передачи по ссылочной структуре (ala std::auto_ptr).

class Test;

struct Test_Ref
{
    Test& ref_;
    Test_Ref( Test& t ) : ref_( t ) { };
private:
    Test_Ref& operator=( Test_Ref const& );
}; // struct Test_Ref

class Test
{
public:
    explicit Test( int f = 0 ) : foo_( f ) { };

    Test( Test& other ) : foo_( other.Detach() ) { };

    Test& operator=( Test& other )
    {
        foo_ = other.Detach();
        return *this;
    };

    Test( Test_Ref other ) : foo_( other.ref_.Detach() ) { };

    Test& operator=( Test_Ref other )
    {
        foo_ = other.ref_.Detach();
        return *this;
    };

    operator Test_Ref() { return Test_Ref( *this ); };

private:

    int Detach()
    {
        int tmp = foo_;
        foo_ = 0;
        return tmp;
    };

    // resource that cannot be copied. 
    int foo_;
}; // class Test

К сожалению, когда я использую этот шаблон с библиотекой, которая использует размещение-новое, я получаю ошибку компилятора:

.\test.cpp(58) : error C2558: class 'Test' : no copy constructor available or copy constructor is declared 'explicit'
    .\test.cpp(68) : see reference to function template instantiation 'void Copy<Test>(T *,const T &)' being compiled
    with
    [
        T=Test
    ]

Например:

template< class T > inline void Copy( T* p, const T& val ) 
{
    new( p ) T( val );
}

int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
    Test* __p = new Test();
    Test __val;
    Copy( __p, __val );
    return 0;
}

Как я могу изменить Test так, чтобы его можно было использовать с новым размещением и при этом сохранить семантику его владения?

Спасибо, PaulH

Ответы [ 2 ]

1 голос
/ 17 мая 2011

Сосредоточив внимание на функции main, поскольку это должно указывать на предполагаемую семантику, существуют две большие проблемы: во-первых, вы не выделяете память, что означает, что если компилятор обработает код, он вызовет UBпопробуйте вызвать конструктор Test по адресу NULL в новой операции размещения.

Другая проблема хорошо известна пользователям std::auto_ptr: подпись конструктора копирования принимает нессылка const, и это означает, что вы не можете вызвать ее для объекта const. С другой стороны вы пытаетесь вызвать конструктор копирования внутри шаблона Copy, который обещал не изменять объект, на который ссылаетсяВторой аргумент:

template <typename T>
void Copy( T* p, T& o ) {
   new (p) T( o );         // would work, object is non-const
}

Наконец, я не уверен, если это связано с копированием в вопрос, но я не уверен, каковы ваши намерения с классом эталонной оболочки, который вы предоставляете в начале, поэтомуВы можете уточнить.

0 голосов
/ 17 мая 2011

Ваша проблема не имеет ничего общего с размещением новых.В void Copy вы попытались скопировать объект типа Test, но запретили копирование.Это проблема.Также вы попытались разместить новый на NULL.Вы не смогли правильно реализовать структуру, потому что constness- operator test_ref() никогда не может быть вызван, потому что вы взяли const T& и это неконстантный оператор.Это означает, что если вы не хотите удивлять людей ходами, когда они думают, что это должны быть копии, вы не сможете этого сделать.

...