Related
My default behaviour for any objects in local scopes is to make it const. E.g.:
auto const cake = bake_cake(arguments);
I try to have as little non-functional code as I can as this increases readability (and offers some optimisation opportunities for the compiler). So it is logical to also reflect this in the type system.
However, with move semantics, this creates the problem: what if my cake is hard or impossible to copy and I want to pass it out after I'm done with it? E.g.:
if (tastes_fine(cake)) {
return serve_dish(cake);
}
As I understand copy elision rules it's not guaranteed that the cake copy will be elided (but I'm not sure on this).
So, I'd have to move cake out:
return serve_dish(std::move(cake)); // this will not work as intended
But that std::move will do nothing useful, as it (correctly) will not cast Cake const& to Cake&&. Even though the lifetime of the object is very near its end. We cannot steal resources from something we promised not to change. But this will weaken const-correctness.
So, how can I have my cake and eat it too?
(i.e. how can I have const-correctness and also benefit from move semantics.)
I believe it's not possible to move from a const object, at least with a standard move constructor and non-mutable members. However, it is possible to have a const automatic local object and apply copy elision (namely NRVO) for it. In your case, you can rewrite your original function as follows:
Cake helper(arguments)
{
const auto cake = bake_cake(arguments);
... // original code with const cake
return cake; // NRVO
}
Then, in your original function, you can just call:
return serve_dish(helper(arguments));
Since the object returned by helper is already a non-const rvalue, it may be moved-from (which may be, again, elided, if applicable).
Here is a live-demo that demonstrates this approach. Note that there are no copy/move constructors called in the generated assembly.
You should indeed continue to make your variables const as that is good practice (called const-correctness) and it also helps when reasoning about code - even while creating it. A const object cannot be moved from - this is a good thing - if you move from an object you are almost always modifying it to a large degree or at least that is implied (since basically a move implies stealing the resources owned by the original object) !
From the core guidelines:
You can’t have a race condition on a constant. It is easier to reason
about a program when many of the objects cannot change their values.
Interfaces that promises “no change” of objects passed as arguments
greatly increase readability.
and in particular this guideline :
Con.4: Use const to define objects with values that do not change
after construction
Moving on to the next, main part of the question:
Is there a solution that does not exploit NRVO?
If by NRVO you take to include guaranteed copy elision, then not really, or yes and no at the same. This is somewhat complicated. Trying to move the return value out of a return by value function doesn't necessarily do what you think or want it to. Also, a "no copy" is always better than a move performance-wise. Therefore, instead you should try to let the compiler do it's magic and rely in particular on guaranteed copy elision (since you use c++17). If you have what I would call a complex scenario where elision is not possible: you can then use a move combined with guaranteed copy elision/NRVO, so as to avoid a full copy.
So the answer to that question is something like: if you object is already declared as const, then you can almost always rely on copy-elision/return by value directly, so use that. Otherwise you have some other scenario and then use discretion as to the best approach - in rare cases a move could be in order(meaning it's combined with copy-elision).
Example of 'complex' scenario:
std::string f() {
std::string res("res");
return res.insert(0, "more: ");//'complex scenario': a reference gets returned here will usually mean a copy is invoked here.
}
Superior way to 'fix' is to use copy-elision i.e.:
return res;//just return res as we already had that thus avoiding copy altogether - it's possible that we can't use this solution for more *hairy/complex* scenarios.
Inferior way to 'fix' in this example would be;
return std::move(res.insert(0, "more: "));
Make them movable if you can.
It's time to change your "default behaviour" as it's anachronistic.
If move semantics were built into the language from inception then making automatic variables const would have quickly become established as poor programming practice.
const was never intended to be used for micro-optimisations. Micro-optimisations are best left to the compiler. const exists primarily for member variables and member functions. It's also helped clean up the language a little: e.g. "foo" is a const char[4] type whereas in C it's a char[4] type with the curious understanding that you're not allowed to modify the contents.
Now (since C++11) const for automatic variables can actually be harmful as you observe, the time has come to stop this practice. The same can be said for const parameter by-value types. Your code would be less verbose too.
Personally I prefer immutable objects to const objects.
It seems to me, that if you want to move, than it will be "const correct" to not declare it const, because you will(!) change it.
It's ideological contradiction. You cannot move something and leave in place at the same time.
You mean, that object will be const for a part of time, in some scope. In this case, you can declare const reference to it, but it seems to me, that this will complicate the code and will add no safety.
Even vice versa, if you accidentally use the const reference to object after std::move() there will be problems, despite it will look like work with const object.
A limited workaround would be const move constructor:
class Cake
{
public:
Cake(/**/) : resource(acquire_resource()) {}
~Cake() { if (owning) release_resource(resource); }
Cake(const Cake& rhs) : resource(rhs.owning ? copy_resource(rhs.resource) : nullptr) {}
// Cake(Cake&& rhs) // not needed, but same as const version should be ok.
Cake(const Cake&& rhs) : resource(rhs.resource) { rhs.owning = false; }
Cake& operator=(const Cake& rhs) {
if (this == &rhs) return *this;
if (owning) release_resource(resource);
resource = rhs.owning ? copy_resource(rhs.resource) : nullptr;
owning = rhs.owning;
}
// Cake& operator=(Cake&& rhs) // not needed, but same as const version should be ok.
Cake& operator=(const Cake&& rhs) {
if (this == &rhs) return *this;
if (owning) release_resource(resource);
resource = rhs.resource;
owning = rhs.owning;
rhs.owning = false;
}
// ...
private:
Resource* resource = nullptr;
// ...
mutable bool owning = true;
};
Require extra mutable member.
not compatible with std containers which will do copy instead of move (providing non const version will leverage copy in non const usage)
usage after move should be considered (we should be in valid state, normally). Either provide owning getter, or "protect" appropriate methods with owning check.
I would personally just drop the const when move is used.
What is the copy-and-swap idiom and when should it be used? What problems does it solve? Does it change for C++11?
Related:
What are your favorite C++ Coding Style idioms: Copy-swap
Copy constructor and = operator overload in C++: is a common function possible?
What is copy elision and how it optimizes copy-and-swap idiom
C++: dynamically allocating an array of objects?
Overview
Why do we need the copy-and-swap idiom?
Any class that manages a resource (a wrapper, like a smart pointer) needs to implement The Big Three. While the goals and implementation of the copy-constructor and destructor are straightforward, the copy-assignment operator is arguably the most nuanced and difficult. How should it be done? What pitfalls need to be avoided?
The copy-and-swap idiom is the solution, and elegantly assists the assignment operator in achieving two things: avoiding code duplication, and providing a strong exception guarantee.
How does it work?
Conceptually, it works by using the copy-constructor's functionality to create a local copy of the data, then takes the copied data with a swap function, swapping the old data with the new data. The temporary copy then destructs, taking the old data with it. We are left with a copy of the new data.
In order to use the copy-and-swap idiom, we need three things: a working copy-constructor, a working destructor (both are the basis of any wrapper, so should be complete anyway), and a swap function.
A swap function is a non-throwing function that swaps two objects of a class, member for member. We might be tempted to use std::swap instead of providing our own, but this would be impossible; std::swap uses the copy-constructor and copy-assignment operator within its implementation, and we'd ultimately be trying to define the assignment operator in terms of itself!
(Not only that, but unqualified calls to swap will use our custom swap operator, skipping over the unnecessary construction and destruction of our class that std::swap would entail.)
An in-depth explanation
The goal
Let's consider a concrete case. We want to manage, in an otherwise useless class, a dynamic array. We start with a working constructor, copy-constructor, and destructor:
#include <algorithm> // std::copy
#include <cstddef> // std::size_t
class dumb_array
{
public:
// (default) constructor
dumb_array(std::size_t size = 0)
: mSize(size),
mArray(mSize ? new int[mSize]() : nullptr)
{
}
// copy-constructor
dumb_array(const dumb_array& other)
: mSize(other.mSize),
mArray(mSize ? new int[mSize] : nullptr)
{
// note that this is non-throwing, because of the data
// types being used; more attention to detail with regards
// to exceptions must be given in a more general case, however
std::copy(other.mArray, other.mArray + mSize, mArray);
}
// destructor
~dumb_array()
{
delete [] mArray;
}
private:
std::size_t mSize;
int* mArray;
};
This class almost manages the array successfully, but it needs operator= to work correctly.
A failed solution
Here's how a naive implementation might look:
// the hard part
dumb_array& operator=(const dumb_array& other)
{
if (this != &other) // (1)
{
// get rid of the old data...
delete [] mArray; // (2)
mArray = nullptr; // (2) *(see footnote for rationale)
// ...and put in the new
mSize = other.mSize; // (3)
mArray = mSize ? new int[mSize] : nullptr; // (3)
std::copy(other.mArray, other.mArray + mSize, mArray); // (3)
}
return *this;
}
And we say we're finished; this now manages an array, without leaks. However, it suffers from three problems, marked sequentially in the code as (n).
The first is the self-assignment test.
This check serves two purposes: it's an easy way to prevent us from running needless code on self-assignment, and it protects us from subtle bugs (such as deleting the array only to try and copy it). But in all other cases it merely serves to slow the program down, and act as noise in the code; self-assignment rarely occurs, so most of the time this check is a waste.
It would be better if the operator could work properly without it.
The second is that it only provides a basic exception guarantee. If new int[mSize] fails, *this will have been modified. (Namely, the size is wrong and the data is gone!)
For a strong exception guarantee, it would need to be something akin to:
dumb_array& operator=(const dumb_array& other)
{
if (this != &other) // (1)
{
// get the new data ready before we replace the old
std::size_t newSize = other.mSize;
int* newArray = newSize ? new int[newSize]() : nullptr; // (3)
std::copy(other.mArray, other.mArray + newSize, newArray); // (3)
// replace the old data (all are non-throwing)
delete [] mArray;
mSize = newSize;
mArray = newArray;
}
return *this;
}
The code has expanded! Which leads us to the third problem: code duplication.
Our assignment operator effectively duplicates all the code we've already written elsewhere, and that's a terrible thing.
In our case, the core of it is only two lines (the allocation and the copy), but with more complex resources this code bloat can be quite a hassle. We should strive to never repeat ourselves.
(One might wonder: if this much code is needed to manage one resource correctly, what if my class manages more than one?
While this may seem to be a valid concern, and indeed it requires non-trivial try/catch clauses, this is a non-issue.
That's because a class should manage one resource only!)
A successful solution
As mentioned, the copy-and-swap idiom will fix all these issues. But right now, we have all the requirements except one: a swap function. While The Rule of Three successfully entails the existence of our copy-constructor, assignment operator, and destructor, it should really be called "The Big Three and A Half": any time your class manages a resource it also makes sense to provide a swap function.
We need to add swap functionality to our class, and we do that as follows†:
class dumb_array
{
public:
// ...
friend void swap(dumb_array& first, dumb_array& second) // nothrow
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two objects,
// the two objects are effectively swapped
swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);
}
// ...
};
(Here is the explanation why public friend swap.) Now not only can we swap our dumb_array's, but swaps in general can be more efficient; it merely swaps pointers and sizes, rather than allocating and copying entire arrays. Aside from this bonus in functionality and efficiency, we are now ready to implement the copy-and-swap idiom.
Without further ado, our assignment operator is:
dumb_array& operator=(dumb_array other) // (1)
{
swap(*this, other); // (2)
return *this;
}
And that's it! With one fell swoop, all three problems are elegantly tackled at once.
Why does it work?
We first notice an important choice: the parameter argument is taken by-value. While one could just as easily do the following (and indeed, many naive implementations of the idiom do):
dumb_array& operator=(const dumb_array& other)
{
dumb_array temp(other);
swap(*this, temp);
return *this;
}
We lose an important optimization opportunity. Not only that, but this choice is critical in C++11, which is discussed later. (On a general note, a remarkably useful guideline is as follows: if you're going to make a copy of something in a function, let the compiler do it in the parameter list.‡)
Either way, this method of obtaining our resource is the key to eliminating code duplication: we get to use the code from the copy-constructor to make the copy, and never need to repeat any bit of it. Now that the copy is made, we are ready to swap.
Observe that upon entering the function that all the new data is already allocated, copied, and ready to be used. This is what gives us a strong exception guarantee for free: we won't even enter the function if construction of the copy fails, and it's therefore not possible to alter the state of *this. (What we did manually before for a strong exception guarantee, the compiler is doing for us now; how kind.)
At this point we are home-free, because swap is non-throwing. We swap our current data with the copied data, safely altering our state, and the old data gets put into the temporary. The old data is then released when the function returns. (Where upon the parameter's scope ends and its destructor is called.)
Because the idiom repeats no code, we cannot introduce bugs within the operator. Note that this means we are rid of the need for a self-assignment check, allowing a single uniform implementation of operator=. (Additionally, we no longer have a performance penalty on non-self-assignments.)
And that is the copy-and-swap idiom.
What about C++11?
The next version of C++, C++11, makes one very important change to how we manage resources: the Rule of Three is now The Rule of Four (and a half). Why? Because not only do we need to be able to copy-construct our resource, we need to move-construct it as well.
Luckily for us, this is easy:
class dumb_array
{
public:
// ...
// move constructor
dumb_array(dumb_array&& other) noexcept ††
: dumb_array() // initialize via default constructor, C++11 only
{
swap(*this, other);
}
// ...
};
What's going on here? Recall the goal of move-construction: to take the resources from another instance of the class, leaving it in a state guaranteed to be assignable and destructible.
So what we've done is simple: initialize via the default constructor (a C++11 feature), then swap with other; we know a default constructed instance of our class can safely be assigned and destructed, so we know other will be able to do the same, after swapping.
(Note that some compilers do not support constructor delegation; in this case, we have to manually default construct the class. This is an unfortunate but luckily trivial task.)
Why does that work?
That is the only change we need to make to our class, so why does it work? Remember the ever-important decision we made to make the parameter a value and not a reference:
dumb_array& operator=(dumb_array other); // (1)
Now, if other is being initialized with an rvalue, it will be move-constructed. Perfect. In the same way C++03 let us re-use our copy-constructor functionality by taking the argument by-value, C++11 will automatically pick the move-constructor when appropriate as well. (And, of course, as mentioned in previously linked article, the copying/moving of the value may simply be elided altogether.)
And so concludes the copy-and-swap idiom.
Footnotes
*Why do we set mArray to null? Because if any further code in the operator throws, the destructor of dumb_array might be called; and if that happens without setting it to null, we attempt to delete memory that's already been deleted! We avoid this by setting it to null, as deleting null is a no-operation.
†There are other claims that we should specialize std::swap for our type, provide an in-class swap along-side a free-function swap, etc. But this is all unnecessary: any proper use of swap will be through an unqualified call, and our function will be found through ADL. One function will do.
‡The reason is simple: once you have the resource to yourself, you may swap and/or move it (C++11) anywhere it needs to be. And by making the copy in the parameter list, you maximize optimization.
††The move constructor should generally be noexcept, otherwise some code (e.g. std::vector resizing logic) will use the copy constructor even when a move would make sense. Of course, only mark it noexcept if the code inside doesn't throw exceptions.
Assignment, at its heart, is two steps: tearing down the object's old state and building its new state as a copy of some other object's state.
Basically, that's what the destructor and the copy constructor do, so the first idea would be to delegate the work to them. However, since destruction mustn't fail, while construction might, we actually want to do it the other way around: first perform the constructive part and, if that succeeded, then do the destructive part. The copy-and-swap idiom is a way to do just that: It first calls a class' copy constructor to create a temporary object, then swaps its data with the temporary's, and then lets the temporary's destructor destroy the old state.
Since swap() is supposed to never fail, the only part which might fail is the copy-construction. That is performed first, and if it fails, nothing will be changed in the targeted object.
In its refined form, copy-and-swap is implemented by having the copy performed by initializing the (non-reference) parameter of the assignment operator:
T& operator=(T tmp)
{
this->swap(tmp);
return *this;
}
There are some good answers already. I'll focus mainly on what I think they lack - an explanation of the "cons" with the copy-and-swap idiom....
What is the copy-and-swap idiom?
A way of implementing the assignment operator in terms of a swap function:
X& operator=(X rhs)
{
swap(rhs);
return *this;
}
The fundamental idea is that:
the most error-prone part of assigning to an object is ensuring any resources the new state needs are acquired (e.g. memory, descriptors)
that acquisition can be attempted before modifying the current state of the object (i.e. *this) if a copy of the new value is made, which is why rhs is accepted by value (i.e. copied) rather than by reference
swapping the state of the local copy rhs and *this is usually relatively easy to do without potential failure/exceptions, given the local copy doesn't need any particular state afterwards (just needs state fit for the destructor to run, much as for an object being moved from in >= C++11)
When should it be used? (Which problems does it solve [/create]?)
When you want the assigned-to objected unaffected by an assignment that throws an exception, assuming you have or can write a swap with strong exception guarantee, and ideally one that can't fail/throw..†
When you want a clean, easy to understand, robust way to define the assignment operator in terms of (simpler) copy constructor, swap and destructor functions.
Self-assignment done as a copy-and-swap avoids oft-overlooked edge cases.‡
When any performance penalty or momentarily higher resource usage created by having an extra temporary object during the assignment is not important to your application. ⁂
† swap throwing: it's generally possible to reliably swap data members that the objects track by pointer, but non-pointer data members that don't have a throw-free swap, or for which swapping has to be implemented as X tmp = lhs; lhs = rhs; rhs = tmp; and copy-construction or assignment may throw, still have the potential to fail leaving some data members swapped and others not. This potential applies even to C++03 std::string's as James comments on another answer:
#wilhelmtell: In C++03, there is no mention of exceptions potentially thrown by std::string::swap (which is called by std::swap). In C++0x, std::string::swap is noexcept and must not throw exceptions. – James McNellis Dec 22 '10 at 15:24
‡ assignment operator implementation that seems sane when assigning from a distinct object can easily fail for self-assignment. While it might seem unimaginable that client code would even attempt self-assignment, it can happen relatively easily during algo operations on containers, with x = f(x); code where f is (perhaps only for some #ifdef branches) a macro ala #define f(x) x or a function returning a reference to x, or even (likely inefficient but concise) code like x = c1 ? x * 2 : c2 ? x / 2 : x;). For example:
struct X
{
T* p_;
size_t size_;
X& operator=(const X& rhs)
{
delete[] p_; // OUCH!
p_ = new T[size_ = rhs.size_];
std::copy(p_, rhs.p_, rhs.p_ + rhs.size_);
}
...
};
On self-assignment, the above code delete's x.p_;, points p_ at a newly allocated heap region, then attempts to read the uninitialised data therein (Undefined Behaviour), if that doesn't do anything too weird, copy attempts a self-assignment to every just-destructed 'T'!
⁂ The copy-and-swap idiom can introduce inefficiencies or limitations due to the use of an extra temporary (when the operator's parameter is copy-constructed):
struct Client
{
IP_Address ip_address_;
int socket_;
X(const X& rhs)
: ip_address_(rhs.ip_address_), socket_(connect(rhs.ip_address_))
{ }
};
Here, a hand-written Client::operator= might check if *this is already connected to the same server as rhs (perhaps sending a "reset" code if useful), whereas the copy-and-swap approach would invoke the copy-constructor which would likely be written to open a distinct socket connection then close the original one. Not only could that mean a remote network interaction instead of a simple in-process variable copy, it could run afoul of client or server limits on socket resources or connections. (Of course this class has a pretty horrid interface, but that's another matter ;-P).
This answer is more like an addition and a slight modification to the answers above.
In some versions of Visual Studio (and possibly other compilers) there is a bug that is really annoying and doesn't make sense. So if you declare/define your swap function like this:
friend void swap(A& first, A& second) {
std::swap(first.size, second.size);
std::swap(first.arr, second.arr);
}
... the compiler will yell at you when you call the swap function:
This has something to do with a friend function being called and this object being passed as a parameter.
A way around this is to not use friend keyword and redefine the swap function:
void swap(A& other) {
std::swap(size, other.size);
std::swap(arr, other.arr);
}
This time, you can just call swap and pass in other, thus making the compiler happy:
After all, you don't need to use a friend function to swap 2 objects. It makes just as much sense to make swap a member function that has one other object as a parameter.
You already have access to this object, so passing it in as a parameter is technically redundant.
I would like to add a word of warning when you are dealing with C++11-style allocator-aware containers. Swapping and assignment have subtly different semantics.
For concreteness, let us consider a container std::vector<T, A>, where A is some stateful allocator type, and we'll compare the following functions:
void fs(std::vector<T, A> & a, std::vector<T, A> & b)
{
a.swap(b);
b.clear(); // not important what you do with b
}
void fm(std::vector<T, A> & a, std::vector<T, A> & b)
{
a = std::move(b);
}
The purpose of both functions fs and fm is to give a the state that b had initially. However, there is a hidden question: What happens if a.get_allocator() != b.get_allocator()? The answer is: It depends. Let's write AT = std::allocator_traits<A>.
If AT::propagate_on_container_move_assignment is std::true_type, then fm reassigns the allocator of a with the value of b.get_allocator(), otherwise it does not, and a continues to use its original allocator. In that case, the data elements need to be swapped individually, since the storage of a and b is not compatible.
If AT::propagate_on_container_swap is std::true_type, then fs swaps both data and allocators in the expected fashion.
If AT::propagate_on_container_swap is std::false_type, then we need a dynamic check.
If a.get_allocator() == b.get_allocator(), then the two containers use compatible storage, and swapping proceeds in the usual fashion.
However, if a.get_allocator() != b.get_allocator(), the program has undefined behaviour (cf. [container.requirements.general/8].
The upshot is that swapping has become a non-trivial operation in C++11 as soon as your container starts supporting stateful allocators. That's a somewhat "advanced use case", but it's not entirely unlikely, since move optimizations usually only become interesting once your class manages a resource, and memory is one of the most popular resources.
When implementing move constructors and move assignment operators, one often writes code like this:
p = other.p;
other.p = 0;
The implicitly defined move operations would be implemented with code like this:
p = std::move(other.p);
Which would be wrong, because moving a pointer variable does not set it to null. Why is that? Are there any cases were we would like the move operations to leave the original pointer variable unchanged?
Note: By "moving", I do not just mean the subexpression std::move(other.p), I mean the whole expression p = std::move(other.p). So, why is there no special language rule that says "If the right hand side of an assignment is a pointer xvalue, it is set to null after the assignment has taken place."?
Setting a raw pointer to null after moving it implies that the pointer represents ownership. However, lots of pointers are used to represent relationships. Moreover, for a long time it is recommended that ownership relations are represented differently than using a raw pointer. For example, the ownership relation you are referring to is represented by std::unique_ptr<T>. If you want the implicitly generated move operations take care of your ownership all you need to do is to use members which actually represent (and implement) the desired ownership behavior.
Also, the behavior of the generated move operations is consistent with what was done with the copy operations: they also don't make any ownership assumptions and don't do e.g. a deep copy if a pointer is copied. If you want this to happen you also need to create a suitable class encoding the relevant semantics.
Moving renders the moved-from object "invalid". It does not automatically set it to a safe "empty" state. In accordance with C++'s long-standing principle of "don't pay for what you don't use", that's your job if you want it.
I think the answer is : implementing such a behavior yourself is pretty much trivial and hence the Standard didn't feel any need to impose any rule on the compiler itself. The C++ language is huge and not everything can be imagined before its use. Take for example, C++'s template. It was not first designed to be used the way it is used today (i.e it's metaprogramming capability). So I think, the Standard just gives the freedom, and didn't make any specific rule for std::move(other.p), following one of it's the design-principle: "You don't pay for what you don't use".
Although, std::unique_ptr is movable, though not copyable. So if you want pointer-semantic which is movable and copyable both, then here is one trivial implementation:
template<typename T>
struct movable_ptr
{
T *pointer;
movable_ptr(T *ptr=0) : pointer(ptr) {}
movable_ptr<T>& operator=(T *ptr) { pointer = ptr; return *this; }
movable_ptr(movable_ptr<T> && other)
{
pointer = other.pointer;
other.pointer = 0;
}
movable_ptr<T>& operator=(movable_ptr<T> && other)
{
pointer = other.pointer;
other.pointer = 0;
return *this;
}
T* operator->() const { return pointer; }
T& operator*() const { return *pointer; }
movable_ptr(movable_ptr<T> const & other) = default;
movable_ptr<T> & operator=(movable_ptr<T> const & other) = default;
};
Now you can write classes, without writing your own move-semantics:
struct T
{
movable_ptr<A> aptr;
movable_ptr<B> bptr;
//...
//and now you could simply say
T(T&&) = default;
T& operator=(T&&) = default;
};
Note that you still have to write copy-semantics and the destructor, as movable_ptr is not smart pointer.
For example, if you have a pointer to a shared object. Remember, that after moving an object must remain in an internally consistent state, so setting a pointer that must not be null to a null value is not correct.
I.e.:
struct foo
{
bar* shared_factory; // This can be the same for several 'foo's
// and must never null.
};
Edit
Here is a quote about MoveConstructibe from the standard:
T u = rv;
...
rv’s state is unspecified [ Note:rv must still meet the requirements
of the library component that is using it. The operations listed in
those requirements must work as specified whether rv has been moved
from or not.
I think what makes the difference here is a fully blown object on the one hand and a POD on the other hand.
For objects either the implementer specifies what move construction and move assignment should do or the compiler generates a default. The default is to call the move constructors/assignment operators of all member.
For POD's (and a pointer is a POD) C++ inherits from C and nothing is done with it when not explicitely coded. It's just the same behavior as POD members in a class are treated in a constructor. If you don't explicitely put them in the initializer list, well, then they stay uninitialized and are a source of potential bugs. AFAIK this is even valid for compiler generated constructors! That's why I took on the habit of generally initializing all members to be on the safe side.
I have several members in my class which are const and can therefore only be initialised via the initialiser list like so:
class MyItemT
{
public:
MyItemT(const MyPacketT& aMyPacket, const MyInfoT& aMyInfo)
: mMyPacket(aMyPacket),
mMyInfo(aMyInfo)
{
}
private:
const MyPacketT mMyPacket;
const MyInfoT mMyInfo;
};
My class can be used in some of our internally defined container classes (e.g. vectors), and these containers require that operator= is defined in the class.
Of course, my operator= needs to do something like this:
MyItemT&
MyItemT::operator=(const MyItemT& other)
{
mMyPacket = other.mPacket;
mMyInfo = other.mMyInfo;
return *this;
}
which of course doesn't work because mMyPacket and mMyInfo are const members.
Other than making these members non-const (which I don't want to do), any ideas about how I could fix this?
You're kind of violating the definition of const if you have an assignment operator that can change them after construction has finished. If you really need to, I think Potatoswatter's placement new method is probably best, but if you have an assignment operator your variables aren't really const, since someone could just make a new instance and use it to change their values
Rather than storing objects in your containers directly, you might be able to store pointers (or smart pointers). That way, you don't have to mutate any of the members of your class -- you get back exactly the same object as you passed in, const and all.
Of course, doing this will probably change the memory management of your application somewhat, which may well be a good enough reason not to want to.
It's a dirty hack, but you can destroy and reconstruct yourself:
MyItemT&
MyItemT::operator=(const MyItemT& other)
{
if ( this == &other ) return *this; // "suggested" by Herb Sutter ;v)
this->MyItemT::~MyItemT();
try {
new( this ) MyItemT( other );
} catch ( ... ) {
new( this ) MyItemT(); // nothrow
throw;
}
return *this;
}
Edit: lest I destroy my credibility, I don't actually do this myself, I would remove the const. However, I've been debating changing the practice, because const simply is useful and better to use wherever possible.
Sometimes there is a distinction between the resource and the value represented by an object. A member may be const through changes to value as long as the resource is the same, and it would be nice to get compile-time safety on that.
Edit 2: #Charles Bailey has provided this wonderful (and highly critical) link: http://gotw.ca/gotw/023.htm.
Semantics are tricky in any derived class operator=.
It may be inefficient because it doesn't invoke assignment operators that have been defined.
It's incompatible with wonky operator& overloads (whatever)
etc.
Edit 3: Thinking through the "which resource" vs "what value" distinction, it seems clear that operator= should always change the value and not the resource. The resource identifier may then be const. In the example, all the members are const. If the "info" is what's stored inside the "packet," then maybe the packet should be const and the info not.
So the problem isn't so much figuring out the semantics of assignment as lack of an obvious value in this example, if the "info" is actually metadata. If whatever class owns a MyItemT wants to switch it from one packet to another, it needs to either give up and use an auto_ptr<MyItemT> instead, or resort to a similar hack as above (the identity test being unnecessary but the catch remaining) implemented from outside. But operator= shouldn't change resource binding except as an extra-special feature which absolutely won't interfere with anything else.
Note that this convention plays well with Sutter's advice to implement copy construction in terms of assignment.
MyItemT::MyItemT( MyItemT const &in )
: mMyPacket( in.mMyPacket ) // initialize resource, const member
{ *this = in; } // assign value, non-const, via sole assignment method
I think you could get away with a special const proxy.
template <class T>
class Const
{
public:
// Optimal way of returning, by value for built-in and by const& for user types
typedef boost::call_traits<T>::const_reference const_reference;
typedef boost::call_traits<T>::param_type param_type;
Const(): mData() {}
Const(param_type data): mData(data) {}
Const(const Const& rhs): mData(rhs.mData) {}
operator const_reference() const { return mData; }
void reset(param_type data) { mData = data; } // explicit
private:
Const& operator=(const Const&); // deactivated
T mData;
};
Now, instead of const MyPacketT you would have Const<MyPacketT>. Not that the interface only provides one way to change it: through an explicit call to reset.
I think any use of mMyPacket.reset can easily be search for. As #MSalters said it protects against Murphy, not Machiavelli :)
You might consider making the MyPacketT and MyInfoT members be pointers to const (or smart pointers to const). This way the data itself is still marked const and immutable, but you can cleanly 'swap' to another set of const data in an assignment if that makes sense. In fact, you can use the swap idiom to perform the assignment in an exception safe manner.
So you get the benefit of const to help you prevent accidentally allowing changes that you want the design to prevent, but you still allow the object as a whole to be assigned from another object. For example, this will let you use objects of this class in STL containers.
You might look at this as a special application of the 'pimpl' idiom.
Something along the lines of:
#include <algorithm> // for std::swap
#include "boost/scoped_ptr.hpp"
using namespace boost;
class MyPacketT {};
class MyInfoT {};
class MyItemT
{
public:
MyItemT(const MyPacketT& aMyPacket, const MyInfoT& aMyInfo)
: pMyPacket(new MyPacketT( aMyPacket)),
pMyInfo(new MyInfoT( aMyInfo))
{
}
MyItemT( MyItemT const& other)
: pMyPacket(new MyPacketT( *(other.pMyPacket))),
pMyInfo(new MyInfoT( *(other.pMyInfo)))
{
}
void swap( MyItemT& other)
{
pMyPacket.swap( other.pMyPacket);
pMyInfo.swap( other.pMyInfo);
}
MyItemT const& operator=( MyItemT const& rhs)
{
MyItemT tmp( rhs);
swap( tmp);
return *this;
}
private:
scoped_ptr<MyPacketT const> pMyPacket;
scoped_ptr<MyInfoT const> pMyInfo;
};
Finally, I changed my example to use scoped_ptr<> instead of shared_ptr<> because I thought it was a more general representation of what the OP intended. However, if the 'reassignable' const members can be shared (and that's probably true, given my understanding of why the OP wants them const), then it might be an optimization to use shared_ptr<>'s and let the copy and assignment operations of the shared_ptr<> class take care of things for those objects - if you have no other members that require special copy or assign sematics, then your class just got a lot simpler, and you might even save a significant bit of memory usage by being able to share copies of the MyPacketT and MyInfoT objects.
I have class foo that contains a std::auto_ptr member that I would like to copy construct but this does not appear to be allowed. There's a similar thing for the assignment. See the following example:
struct foo
{
private:
int _a;
std::string _b;
std::auto_ptr< bar > _c;
public:
foo(const foo& rhs)
: _a(rhs._a)
, _b(rhs._b)
, _c(rhs._c)
// error: Cannot mutate rhs._c to give up ownership - D'Oh!
{
}
foo& operator=(const foo& rhs)
{
_a = rhs._a;
_b = rhs._b;
_c = rhs._c;
// error: Same problem again.
}
};
I could just declare _c as mutable but I'm not sure this is correct. Does anyone have a better solution?
EDIT
OK, I'm not getting the kind of answer that I was expecting so I'll be a little more specific about the problem.
An object of type foo is created on the stack and passed by value into a container class (not stl) and then goes out of scope. I don't have any control over the container code. (It's actually an active queue implementation, with bugs.)
The bar class is a fairly heavyweight parser. It has very poor performance on new and delete so even if it was copy constructable, it would be way too expensive.
We can guarantee that when a bar object is created, it will only ever need to be owned in 1 place at a time. In this case it is being passed between threads and deleted when the transaction is completed. This is why I was hoping to use a std::autp_ptr.
I am very willing to consider boost smart pointers but I was hoping to guarantee this uniqueness if there is an alternative.
You might want to try following code:
foo(const foo& rhs)
: _a(rhs._a)
, _b(rhs._b)
, _c(_rhs._c.get() ? new bar(*_rhs._c.get()) : 0)
{
}
(Assignment operator is similar.)
However this will only work if bar is CopyConstructible and if this indeed does what you want. The thing is that both foo objects (_rhs and constructed one) will have different pointers in _c.
If you want them to share the pointer then you must not use auto_ptr as it does not support shared ownership. Consider in such case use of shared_ptr from Boost.SmartPtr for example (which will be included in new C++ standard). Or any other shared pointer implementation as this is such a common concept that lots of implementations are available.
As you have discovered you can't copy a std::auto_ptr like that. After the copy who owns the object pointed to? Instead you should use a reference counted smart pointer. The Boost library has a shared_ptr you could use.
First, I'd avoid auto_ptr
Transfer of ownership is good in some scenarios, but I find they are rare, and "full fledged" smart pointer libraries are now available easily. (IIRC auto_ptr was a compromise to include at least one example in the standard library, without the delays that a good implementation would have required).
See, for example here
or here
Decide on semantics
Should the copy of foo hold a reference to the same instance of bar? In that case, use boost::shared_ptr or (boost::intrusive_ptr), or a similar library.
Or should a deep copy be created?
(That may sometimes be required, e.g. when having delay-created state). I don't know any standard implementation of that concept, but it's not to complex to build that similar to existing smart pointers.
// roughly, incomplete, probably broken:
template <typename T>
class deep_copy_ptr
{
T * p;
public:
deep_copy_ptr() : p(0) {}
deep_copy_ptr(T * p_) : p(p_) {}
deep_copy_ptr(deep_copy_ptr<T> const & rhs)
{
p = rhs.p ? new T(*rhs.p) : 0;
}
deep_copy_ptr<T> & operator=(deep_copy_ptr<T> const & rhs)
{
if (p != rhs.p)
{
deep_copy_ptr<T> copy(rhs);
swap(copy);
}
}
// ...
}
The std::auto_ptr is a good tool for managing dynamic object in C++ but in order to use it effectivelly it's important to unserstand how auto_ptr works. This article explains why, when and where this smart pointer should be used.
In your case, first of all your should decide what you want to do with the object inside your auto_ptr. Should it be cloned or shared?
If it should be cloned, make sure it has a copy constructor and then your create a new auto_ptr which contains a copy of your the object see Adam Badura's answer.
If it should shared, you should use boost::shared_ptr as Martin Liversage suggested.
If I have class containing an auto_ptr, and want deep-copy semantics, I generatally only do this for classes that have a virtual copy operator, i.e. clone().
Then, within the copy constructor, I initialize the auto_ptr to a clone() of the other; e.g.
class Foo
{
public:
Foo(const Foo& rhs) : m_ptr(rhs.m_ptr->clone());
private:
std::auto_ptr<T> m_ptr;
};
clone() is typically implemented as follows:
class T
{
std::auto_ptr<T> clone() const
{
return std::auto_ptr<T>(new T(*this));
}
};
We are imposing the condition that T is clonable, but this condition is essentially imposed by having a copiable class with an auto_ptr member.
The whole idea of the auto_ptr is that there's only one owner of the referred to object. This implies you cannot copy the pointer without removing the original ownership.
Since you cannot copy it, you also can't copy an object containing an auto_ptr.
You might try to use move-semantics by e.g. using std::swap instead of copy.
My first choice would be to avoid auto_ptr in this situation altogether. But if I were backed against a wall, I might try to use the keyword mutable in the declaration of _c - this will allow it to be modified even from a const reference.
Given the edit, then it appears you want tranfer of ownership semantics.
In that case, then you'll want to have your copy constructor and assignment operator accept non-const references to their arguments, and perform the initialization/assignment there.
You can't use const references in a copy constructor or assignment operator that involves an auto_ptr<>. Remove the const. In other words, use declarations like
foo(foo & rhs);
foo & operator=(foo & rhs);
These forms are explicitly mentioned in the Standard, primarily in section 12.8. They should be usable in any standard-conforming implementation. In fact, paragraphs 5 and 10 of 12.8 says that the implicitly defined copy constructor and assignment operator (respectively) will take a non-const reference if any of the members require it.