Reputation: 17708
Before anything else, let me take you all into the highway of my thoughts (to say it simply, I'm just imagining these things)
Suppose, I am using a third-party library class that uses move semantics (r-value references). Here is its definition:
class VeryHeavyObject {
VeryHeavyObject(const VeryHeavyObject& obj); // copy constructor
VeryHeavyObject& operator= (const VeryHeavyObject& obj); // copy operator
public:
VeryHeavyObject(); // constructor
VeryHeavyObject(VeryHeavyObject&& obj); // move constructor
VeryHeavyObject& operator= (VeryHeavyObject&& obj); // move operator
// ....
};
Apparently, the author's really concerned about the cost of copying of VeryHeavyObject
and decided to force everything to be moved (More apparently, he doesn't know how to design classes with move semantics). But then, in some point of my code, I need to have a copy of VeryHeavyObject
.
Well, the core question is: How can I copy an object with only a move constructor and a move operator?
P.S.: I have tried but I can't really contact the author of the library (I think he's on vacation).
Upvotes: 1
Views: 877
Reputation: 279335
It might not be possible.
The class has declared the copies private, but we can't see whether the functions are ever defined. You seem to assume that the class has a copy operation that it's hiding away from you to stop you doing something slow, but that might not be the case. Some objects simply cannot be copied. For examples, consider streams.
You wouldn't expect privately-declared-but-not-defined functions in C++11, but there's no law against it. Anyway even if there is an implemented private copy function, it's probably private for a reason (maybe it can only be used under certain controlled circumstances: the class internals know how to use it safely and you don't). So if there's no public copy, then as far as this class's API is concerned it cannot be copied.
Perhaps the class has enough public accessors, that you can interrogate it for the state you need, and construct a new object that matches it. If so then you could reasonably complain to the author of the class that it should be publicly copyable. If not then maybe it has state that can't be duplicated.
Anything that provides unique access to something (streams, drivers, locks) has a reason not to be copyable, because the original and the copy can't both provide unique access to the same thing. Admittedly dup
means that even file descriptors don't physically provide unique access to something, let alone the streams that wrap them. But a stream has state involving buffered data not yet written, which means that copying them would introduce complexity that the class is designed to protect you from. So logically you normally use a stream as though it is the only way to access something.
If the copy assignment operator is implemented, then you might be able to hack a way to call it even though it's private. That won't work for the copy constructor, though, you can't take pointers to constructors. As a brutal hack you could #define private public
before including its header: it's undefined behavior but it might work on the implementation you're using. Forking the third-party source would be better.
Upvotes: 2
Reputation: 76856
In general, it is not possible without modifying the class, because there might be private data that you cannot access. It might be possible if a shallow copy is sufficient, because then you should be able to do it with a memccpy
. (Note that if the class does not have any virtual members or pointers, shallow and deep copy are the same).
Upvotes: 1
Reputation: 300129
You cannot.
However, provided that you have sufficient access to its internals (getters and the like), then you can construct a clone by yourself.
Upvotes: 6
Reputation: 11038
A well defined interface, and we will assume that this is the case, some methods may not be available because the author wants to discourage certain uses for performance reasons. A well-known example is std::list
, which does not include a []
operator because it has O(n)
complexity compared with O(1)
in other containers, such as std::vector
.
In this case, the author of the library wants to discourage the use of copies because, as you state in your question, it is very costly. But this does not mean that it is impossible. If you really need to do it, you can probably write your own Clone()
function that takes data from the original VeryHeavyObject
as appropriate, constructs a new one with these data and returns it using std::move
. Since we haven't got the interface for VeryHeavyObject
we cannot try to do it, but I'm sure you can.
Upvotes: 2