Object that transfers ownership on assignment/copy
As a possible solution to a problem I'm trying to solve with an
iterator (see an earlier post by me with subject "Iterator
implementation questions: copy constructor and postfix increment"),
I'm trying to implement an object that transfers ownership on
assignment or copy, just like auto_ptr does.
With an auto_ptr, I can do this:
#include <string>
#include <memory>
#include <iostream>
using namespace std;
auto_ptr<string> ap_factory() {
return auto_ptr<string>(new string("foo"));
}
int main() {
auto_ptr<string> s = ap_factory();
auto_ptr<string> s2 = s;
cout << "s1=" << s.get() << ", s2=" << *s2 << endl;
}
and when "s2 = s" executes, the pointer that was held by "s" is
trasferred to "s2", and then the pointer in "s" is set to NULL. So, I
see this output:
s1=0, s2=foo
When I try to implement the same behavior in my own class, I have
compilation problems. Here's my small test case:
#include <string>
#include <iostream>
using namespace std;
class C {
public:
C(string *_s) : s(_s) { }
C(C &that) : s(that.s) { }
C& operator=(C &that) {
if (&that != this) {
s = that.s;
}
return *this;
}
const string *get() {
return s.get();
}
private:
auto_ptr<string> s;
};
C c_factory() {
return C(new string("foo"));
}
int main() {
C myC = c_factory();
C myC2 = myC;
cout << "myC=" << myC.get() << ", myC2 = " << *(myC2.get()) << endl;
return 0;
}
When I try to compile this, I get:
test8.C: In function C c_factory():
test8.C:28: error: no matching function for call to C::C(C)
test8.C:10: note: candidates are: C::C(C&)
test8.C:8: note: C::C(std::string*)
test8.C: In function int main():
test8.C:32: error: no matching function for call to C::C(C)
test8.C:10: note: candidates are: C::C(C&)
test8.C:8: note: C::C(std::string*)
The problem seems to be that class C doesn't have a copy constructor
for "const C&" but only "C&", which is appropriate since the copied
object will be destroyed. I can verify this is the problem by
creating a constructor for "const C&", and making s mutable so I can
change it without the compiler complaining:
#include <string>
#include <iostream>
using namespace std;
class C {
public:
C(string *_s) : s(_s) { }
C(C const &that) : s(that.s) { }
C& operator=(C &that) {
if (&that != this) {
s = that.s;
}
return *this;
}
const string *get() {
return s.get();
}
private:
mutable auto_ptr<string> s;
};
C c_factory() {
return C(new string("foo"));
}
int main() {
C myC = c_factory();
C myC2 = myC;
cout << "myC=" << myC.get() << ", myC2 = " << *(myC2.get()) << endl;
return 0;
}
compiles and gives the expected output:
myC=0, myC2 = foo
Clearly, though, using "mutable" in this way is a hack.
Is there a better solution to this problem? auto_ptr seems not to have
a copy constructor that requires a const object, so there must be a
way, but I've looked at the source code for g++'s auto_ptr and can't
figure out what magic is making this work.
Thanks for any advice,
----ScottG.