Question

I have a Visual Studio 2008 C++ project with a class that manages a resource that cannot be copied. I have implemented transfer-by-reference-structure semantics (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

Unfortunately, when I use this pattern with a library that uses placement-new, I get a compiler error:

.\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
    ]

For example:

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;
}

How can I modify Test such that it can be used with placement new and still retain its ownership semantics?

Thanks, PaulH

Was it helpful?

Solution

Focusing on the main function, as that should indicate your intended semantics, there are two big problems: First, you are not allocating memory, which means that if the compiler would process the code, it would cause UB (would try to call the constructor of Test over the NULL address in the placement new operation.

The other issue is well known to users of std::auto_ptr: The signature of the copy constructor takes a non-const reference, and that means that you cannot call it on a const object. On the other end you are trying to call the copy constructor inside the Copy template that promised not to change the object referenced by the second argument:

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

Finally, I am not sure if due to copying into the question, but I am not sure of what your intentions are with the reference wrapper class that you are providing in the beginning, so you might want to clarify.

OTHER TIPS

Your problem has nothing to do with placement new. In void Copy then you attempted to copy an object of type Test, but you disallow copying. That's the problem. Also, you attempted to placement new on NULL. You failed to implement the structure properly because of the constness- operator test_ref() can never be called because you took a const T& and it's a non-const operator. This means that unless you want to surprise people with moves when they think it should be copies, you cannot do this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top