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