* lutorm:
Is the statement that it's impossible to return an object containing an
auto_ptr by value true?
No.
#include <memory>
class Bad
{
private:
std::auto_ptr<int> p;
Bad() {};
public:
static Bad instance()
{
Bad result;
return result;
}
};
int main()
{
Bad::instance();
}
Here the compiler-generated copy constructor has (of necessity, due to the
auto_ptr which modifies the source in a copy) non-const argument.
However, because of that non-const argument you cannot write
Bad o( Bad::instance() );
or
Bad o = Bad::instance();
because that requires a copy constructor with const argument, because a
temporary is an rvalue and and an rvalue, such as the number 42, is not
something you'd ordinarily want to modify, so it doesn't match the non-
const reference argument.
So even though you can return the value, the caller cannot use it directly
to initialize a variable -- at least not without breaking const
correctness.
It seems bizarre to me... Correct me if I'm
wrong, but in principle it doesn't seem to be anything wrong with doing
this? As I understand, this is what happens when make_A() is called:
1. create A-object temp
2. when returning from make_A(), call "aa.A::A(A& temp)" to copy
construct aa from temp
3. destroy temp
it doesn't seem like there's anything wrong with any of these steps.
temp isn't destroyed until the copy constructor has completed. I mean,
it works to return auto_ptrs by value, so why not an object containing
an auto_ptr?
std::auto_ptr uses very dirty hacks to allow something that _looks like_
copy construction -- but isn't, really.
Let's examine a concrete case,
#include <memory>
int main()
{
std::auto_ptr<int> x = std::auto_ptr<int>( 0 );
}
Which constructor is involved here (assuming the compiler doesn't
optimize away the temporary, which I think it's allowed to do)?
One would guess the copy constructor with const argument, but if so then
it would break const correctness.
Instead, what happens is logically equivalent to (1) a conversion of the
temporary to std::auto_ptr_ref, and (2) use of that std::auto_ptr_ref
object as argument to the destination std::auto_ptr object's constructor.
(1) is allowed because you're allowed to call member functions, such as
conversion operators, on temporary objects, and (2) is just the usual, so
that the code above is logically equivalent to
#include <memory>
int main()
{
std::auto_ptr<int> temp( 0 );
std::auto_ptr_ref<int> ref( temp );
std::auto_ptr<int> x( ref );
}
So, you _can_, in principle, use this dirty technique yourself:
#include <memory>
class ARef
{
friend class A;
private:
A* myRef;
A& object() { return *myRef; }
public:
ARef( A& aRef ): myRef( &aRef ) {}
};
class A
{
friend class maker_of_A;
private:
std::auto_ptr<float> a;
A(){};
public:
A( ARef ref ): a( ref.object().a ) {}
operator ARef() { return ARef( *this ); }
};
class maker_of_A
{
public:
A instance() { return A(); }
};
int main()
{
A o = maker_of_A().instance();
}
And here you see more clearly what's going on: copying is implemented by
turning a reference into a pointer (which can be copied by assignment),
and back again, and the source of the copy operation is modified by the
auto_ptr in there.
There has been some debate about whether it's really allowed, because
seemingly there are _two_ user-defined conversions involved. I'm not sure
about the consensus for that, but I know there are fancy implementations
of something like std::auto_ptr that are said to be somehow more conforming.
Anyway, it works in practice, but it's very dirty.
sorry for belabouring this, but I'd like to understand exactly why this
is forbidden and why it makes sense that it is.
Not forbidden, but made hard, because in a logical copy operation one does
not really expect the object being copied to be changed, and it's much
better that the language helps out to _ensure_ that that doesn't happen by
accident -- you should really Really REALLY know what you're doing.
Disclaimer: writing this at the go-to-bed-soon stage of my day, so there may
be slightly incorrect or even untrue statements up there; I trust somebody
will correct things if so.