I have a C++ class that contains a non-copyable handle. The class, however, must have a copy constructor. So, I've implemented one that transfers ownership of the handle to the new object (as below),
class Foo
{
public:
    Foo() : h_( INVALID_HANDLE_VALUE )
    {
    };
    // transfer the handle to the new instance
    Foo( const Foo& other ) : h_( other.Detach() )
    {
    };
    ~Foo()
    {
        if( INVALID_HANDLE_VALUE != h_ )
            CloseHandle( h_ );
    };
    // other interesting functions...
private:
    /// disallow assignment
    const Foo& operator=( const Foo& );
    HANDLE Detach() const
    {
        HANDLE h = h_;
        h_ = INVALID_HANDLE_VALUE;
        return h;
    };
    /// a non-copyable handle
    mutable HANDLE h_;
}; // class Foo
My problem is that the standard copy constructor takes a const-reference and I'm modifying that reference. So, I'd like to know which is better (and why):
a non-standard copy constructor:
Foo( Foo& other );
a copy-constructor that 'lies':
Foo( const Foo& other );
Edit:
DuplicateHandle() only works on specific types of handles. This is not one of them. This handle cannot be duplicated, copied, or cloned. 
Several people have pointed out that I was mistaken in suggesting it is a non-standard copy constructor and that std::auto_ptr does this. I think that's probably the way to go. But, I end up with warnings every time I use the class when I make the copy ctor take a non-const value. For example:
namespace detail {
    class Foo { ... };
};
class Buzz
{
public:
    typedef detail::Foo Fuzz;
    Fuzz bar() const { return Fuzz(); }; // warning here
};
warning C4239: nonstandard extension used : 'argument' : conversion from 'Foo' to 'Foo &'
1> A non-const reference may only be bound to an lvalue; copy constructor takes a reference to non-const
Can anybody suggest what I should do about them?
Edit2:
Everybody seems to be steering me towards std::auto_ptr<>'s method of doing things. So, I looked there and it uses an intermediate structure to get around the issue I described in the first edit. This is the solution I came up with.
class Foo;
struct Foo_ref
{
    explicit Foo_ref( Foo& other ) : ref_( other ) {};
    Foo& ref_;
private:
    const Foo_ref& operator=( const Foo_ref& );
}; // struct Foo_ref
class Foo
{
public:
    Foo() : h_( INVALID_HANDLE_VALUE )
    {
    };
    // transfer the handle to the new instance
    Foo( Foo_ref other ) : h_( other.ref_.Detach() )
    {
    };
    ~Foo()
    {
        if( INVALID_HANDLE_VALUE != h_ )
            CloseHandle( h_ );
    };
    operator Foo_ref()
    {
        Foo_ref tmp( *this );
        return tmp;
    };
    // other interesting functions...
private:
    /// disallow assignment
    const Foo& operator=( const Foo& );
    HANDLE Detach()
    {
        HANDLE h = h_;
        h_ = INVALID_HANDLE_VALUE;
        return h;
    };
    /// a non-copyable handle
    HANDLE h_;
}; // class Foo
It compiles cleanly on warning level 4 and seems to work. Please, let me know if it is somehow more irresponsible than my original post.
Both are horrible. If your class has a member variable which is noncopyable, then your class is noncopyable.
If having your class be noncopyable is really unacceptable, one work around is to have a shared pointer to a "state" class/struct to store noncopyable objects (which itself is noncopyable), but your classes can copy the shared pointer around via the standard copy constructor.
The first option has a well established precedent in the form of auto_ptr:
http://www.cplusplus.com/reference/std/memory/auto_ptr/auto_ptr/
auto_ptr gives up its pointer and is reset when it is copied.
The standard that ensures that a function doesn't change arguments passed as const is much stronger than the copy-ctor standard which is really not very formal.
Also, manipulating a const value by casting away its constness is undefined behavior according to the standard. You can do it if either you are certain that the reference refers to a non-const object or you are passing a const object to a (const-incorrect) function that will not modify the value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With