Let's say I have Foo class:
struct Resource {
void block();
void unblock();
};
struct Foo {
static Foo create() {
Resource resource;
resource.block();
return Foo{resource};
}
~Foo() { resource.unblock(); }
void f() {}
private:
Resource resource;
Foo(Resource resource): resource(resource) {}
};
Am I right and there is no guarantee that ~Foo will be called only once in such block?
{
Foo foo = Foo::create();
foo.f();
}
If there is no guarantee, is it possible to fix somehow if using c++11 and move semantic? For example not call unblock_resource in moved foo, but I am not sure is there guarantee to use move constructor/operator= in return from Foo::create?
Copy elision won't help you, since it is an optimization and may or may not be applied.
Move semantics do help, and you get guaranteed moves in function return of local variables. But that means you have to write the move constructor, and you have to modify the destructor so that it doesn't unlock the resource of an object that was moved from.
Not sure about how this is related to the factory pattern, but to answer your question "Am I right and there is no guarantee that ~Foo will be called only once in such block?":
Avoiding copying/moving objects used as return values (i.e. return value optimization, especially named return value optimization) is permitted, but not guaranteed:
Under the following circumstances, the compilers are permitted, but
not required to omit the copy- and move- (since C++11)construction of
class objects even if the copy/move (since C++11) constructor and the
destructor have observable side-effects. This is an optimization: even
when it takes place and the copy-/move-constructor is not called, it
still must be present and accessible (as if no optimization happened
at all), otherwise the program is ill-formed:
If a function returns a class type by value, and the return
statement's expression is the name of a non-volatile object with
automatic storage duration, which isn't a function parameter, or a
catch clause parameter, and which has the same type (ignoring
top-level cv-qualification) as the return type of the function, then
copy/move (since C++11) is omitted. When that local object is
constructed, it is constructed directly in the storage where the
function's return value would otherwise be moved or copied to. This
variant of copy elision is known as NRVO, "named return value
optimization".
One way could be to control locking/unlocking resources in the move constructor and the destructor, just as you mentioned in your question.
Another way could be to make use of shared_ptr, such that creation and deletion of your Foo-object is managed by an RAII-style shared_ptr wrapper. There is just one tricky thing if you want to keep the Foo-constructor private, since make_shared cannot deal with private constructors. To overcome this, you could declare a public constructor taking a parameter of a private data type as parameter. A little bit ugly, and maybe a little bit clumsy due to the shared_ptr-wrapper. But maybe it's at least some inspiration:
struct Foo {
private:
struct private_dummy {};
public:
static shared_ptr<Foo> create() {
shared_ptr<Foo> foo = make_shared<Foo>(private_dummy{});
return foo;
}
~Foo() { cout << "deleted."; }
Foo(struct private_dummy x) { cout << "created."; }
};
void test() {
shared_ptr<Foo> foo = Foo::create();
}
int main() {
test();
//Foo notOK();
}
Rule of 3/5/0. You define a destructor, but not copy / move constructors / assignment operators, which is a red flag that your type is unsafe. Indeed, the destructor may get called twice prior to C++17, and it's easy to mess up while using it even post C++17.
I recommend using std::unique_ptr so that you don't define any copy/move operations or the destructor. You can use std::unique_ptr even if the resource you are managing isn't a pointer; it'd look something like this:
class Resource {
int handle;
public:
Resource(std::nullptr_t = nullptr)
: handle{}
{}
Resource(int handle)
: handle{ handle }
{}
explicit operator bool() const { return handle != 0; }
friend bool operator==(Resource lhs, Resource rhs) { return lhs.handle == rhs.handle; }
friend bool operator!=(Resource lhs, Resource rhs) { return !(lhs == rhs); }
void block() { std::cout << "block\n"; }
void unblock() { std::cout << "unblock\n"; }
struct Deleter {
using pointer = Resource;
void operator()(Resource resource) const {
resource.unblock();
}
};
};
struct Foo {
static Foo create() {
Resource resource{42};
resource.block();
return Foo{resource};
}
void f() {}
private:
std::unique_ptr<Resource, Resource::Deleter> resource;
Foo(Resource resource): resource(resource) {}
};
You are looking for copy-elision.
In short, your code is guaranteed to work in C++17, as described at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
In C++14 and before there is no such guarantee.
Copy elision is an optimization that existed before C++11 and allowed compiler to omit copy constructor call in some cases.
C++11 has added move semantics and copy elision was expanded to allow compiler to avoid moving or copying (if moving is not available) an object.
Regardless of what compiler actually does, your class must still provide copy or move constructor, even if one will not be used by the compiler.
C++17 introduces "guaranteed copy-elision", which allows you to return objects of non-movable classes, just like in your case. Note that proposal explicitly mentions "factory functions". Quote:
it is impossible or very difficult to write factory functions
Example from proposal has this example:
struct NonMoveable {
NonMoveable(int);
NonMoveable(NonMoveable&) = delete;
void NonMoveable(NonMoveable&) = delete;
std::array<int, 1024> arr;
};
NonMoveable make() {
return NonMoveable(42); // ok, directly constructs returned object
}
As of today, both Clang and GCC are able to compile that code with -std=c++17 flag, but not with -std=c++14.
I see two ways for you to solve this problem:
Use C++17: I recommend deleting both copy and move constructor (and operator=) to make sure your code will not compile under earlier standard with buggy effects.
Rely only on things that are available in C++14 to make your code work everywhere. You might want add additional state to your object, delete copy constructor and implement move constructor.
This is an example of how it can be done in C++14.
class Foo {
public:
Foo() = default;
Foo(const Foo &) = delete;
Foo(Foo &&rvalue) noexcept { std::swap(blocked, rvalue.blocked); }
~Foo() { if (blocked) unblock();
void block() { blocked = true; }
void unblock() { blocked = false; }
private:
bool blocked{false};
};
Related
Lets say we have the following class:
class Foo
{
public:
Foo() { _bar=new Bar };
Foo(const Foo &right) { _bar=new Bar(right.bar); };
Foo(Foo &&right) { _bar=right._bar; right.bar=new Bar(); };
~Foo() { delete _bar; }
Foo &operator=(const Foo &right) { _bar->opertor=(right.bar); return *this;}
Foo &operator=(Foo &&right) { std::swap(_bar, right._bar); return *this;}
void func() { _bar->test=1 };
private:
Bar *_bar;
};
is it legitimate to alter it to the following and expect the end user to know that after the move is performed that the rvalue is no longer valid (in that calling anything other than the assignment operator could crash)?
class Foo
{
public:
Foo() { _bar=new Bar };
Foo(const Foo &right) { _bar=new Bar(right.bar); };
Foo(Foo &&right) { _bar=right._bar; right.bar=nullptr; };
~Foo() { if(_bar != nullptr) delete _bar; }
Foo &operator=(const Foo &right)
{
if(_bar == nullptr)
_bar=new Bar();
_bar->opertor=(right.bar);
return *this;
}
Foo &operator=(Foo &&right)
{
if(_bar != nullptr)
delete _bar;
_bar=right._bar;
right._bar=nullptr;
return *this;
}
void func() { _bar->test=1 };
private:
Bar *_bar;
};
my concern comes from the fact that func (and all other functions in the class) assume that _bar exists.
In principle it may become invalid, though you might want consider leaving it in an assignable state (which your original implementation, hence edited, did not do). This would follow the policy of the standard library, which says:
Unless otherwise specified, all standard library objects that have been moved from are placed in a valid but unspecified state. That is, only the functions without preconditions, such as the assignment operator, can be safely used on the object after it was moved from
I'd recommend reimplementing the assignment operator such that it swaps "this" object with a newly constructed one. This is generally a good way to avoid introducing incorrect behaviour when implementing assignments.
A moved-from object is supposed to be in a valid but unspecified state. Note that this is a recommendation but not an absolute requirement of the standard.
Your second code will break if a normal operation is performed on it afterwards (specifically, the copy-assignment operator).
If _bar == nullptr is a valid state then your copy-assignment operator is bugged; if it is not a valid state then I would say your move-constructor is bugged.
NB. In the second code, the if check in the destructor is redundant, as it is legal to delete a null pointer.
is it legitimate to alter it to the following and expect the end user to know that after the move is performed that the rvalue is no longer valid?
You should certainly do that. An rvalue reference is not supposed be kept in an usable state. The idea behind the move constructors and move assignment operators is that you are moving the useful data from the object. I wouldn't use no longer valid to describe it though. It is still a valid object from a C++ point of view just like nullptr is a valid pointer.
The second version is more idiomatic. After an object is moved from it is assumed it will no longer be used.
The check for nullptr before calling delete on the pointer is unnecessary as it is defined in the standard to do nothing.
If the user wishes to use the moved from object, it is his job to make sure it is in a valid state (i.e. assigning from a valid object).
You should document for your Foo what preconditions each member function has, for example:
void Foo::func();
Requires: *this is not in a moved-from state.
Then you're good to go for any of your clients that need to use Foo::func(), unless...
If you use Foo with someone else's library that requires func(), and does not document something along the lines of "except when in a moved-from state", then you're out of luck.
For example: Let's say that your Foo has a operator< like this:
bool operator<(const Foo& x, const Foo& y);
Requries: Neither x nor y may be in a moved-from state.
Now if you do something like:
std::vector<Foo> v;
// ... fill v
std::sort(v.begin(), v.end()); // oops!
The last line above requires Foo to be LessThanComparable whether or not Foo is in a moved-from state. And this is true of all of the generic code in the std::lib. The requires clauses for std code apply to user-supplied code and do not make exceptions for moved-from objects.
However, if your operator< works when either argument is in a moved-from state, then the call to std::sort is fine. This is true even if func() still has the requirement that Foo not be in a moved-from state. This is because std::sort doesn't require func() to work at all.
So in summary, it all depends on what other code your Foo interacts with. Maybe it is ok, and maybe it is not. Document what Foo does, and understand the requirements of the code you use Foo with.
(possibly related to How to implement a C++ method that creates a new object, and returns a reference to it which is about something different, but incidentially contains almost exactly the same code)
I would like to return a reference to a static local from a static function. I can get it to work, of course, but it's less pretty than I'd like.
Can this be improved?
The background
I have a couple of classes which don't do much except acquire or initialize a resource in a well-defined manner and reliably, and release it. They don't even need to know an awful lot about the resource themselves, but the user might still want to query some info in some way.
That's of course trivially done:
struct foo { foo() { /* acquire */ } ~foo(){ /* release */ } };
int main()
{
foo foo_object;
// do stuff
}
Trivial. Alternatively, this would work fine as well:
#include <scopeguard.h>
int main
{
auto g = make_guard([](){ /* blah */}, [](){ /* un-blah */ });
}
Except now, querying stuff is a bit harder, and it's less pretty than I like. If you prefer Stroustrup rather than Alexandrescu, you can include GSL instead and use some concoction involving final_act. Whatever.
Ideally, I would like to write something like:
int main()
{
auto blah = foo::init();
}
Where you get back a reference to an object which you can query if you wish to do that. Or ignore it, or whatever. My immediate thought was: Easy, that's just Meyer's Singleton in disguise. Thus:
struct foo
{
//...
static bar& init() { static bar b; return b; }
};
That's it! Dead simple, and perfect. The foo is created when you call init, you get back a bar that you can query for stats, and it's a reference so you are not the owner, and the foo automatically cleans up at the end.
Except...
The issue
Of course it couldn't be so easy, and anyone who has ever used range-based for with auto knows that you have to write auto& if you don't want surprise copies. But alas, auto alone looked so perfectly innocent that I didn't think of it. Also, I'm explicitly returning a reference, so what can auto possibly capture but a reference!
Result: A copy is made (from what? presumably from the returned reference?) which of course has a scoped lifetime. Default copy constructor is invoked (harmless, does nothing), eventually the copy goes out of scope, and contexts are released mid-operation, stuff stops working. At program end, the destructor is called again. Kaboooom. Huh, how did that happen.
The obvious (well, not so obvious in the first second!) solution is to write:
auto& blah = foo::init();
This works, and works fine. Problem solved, except... except it's not pretty and people might accidentially just do it wrong like I did. Can't we do without needing an extra ampersand?
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
By deleting the copy constructor, I can prevent innocent users from running into the forgot-& trap (this will then cause a compiler error).
That is however still less pretty than I would like. There must be a way of communicating "This return value is to be taken as reference" to the compiler? Something like return std::as_reference(b);?
I had thought about some con trick involving "moving" the object without really moving it, but not only will the compiler almost certainly not let you move a static local at all, but if you manage to do it, you have either changed ownership, or with a "fake move" move-constructor again call the destructor twice. So that's no solution.
Is there a better, prettier way, or do I just have to live with writing auto&?
Something like return std::as_reference(b);?
You mean like std::ref? This returns a std::reference_wrapper<T> of the value you provide.
static std::reference_wrapper<bar> init() { static bar b; return std::ref(b); }
Of course, auto will deduce the returned type to reference_wrapper<T> rather than T&. And while reference_wrapper<T> has an implicit operatorT&, that doesn't mean the user can use it exactly like a reference. To access members, they have to use -> or .get().
That all being said however, I believe your thinking is wrong-headed. The reason is that auto and auto& are something that every C++ programmer needs to learn how to deal with. People aren't going to make their iterator types return reference_wrappers instead of T&. People don't generally use reference_wrapper in that way at all.
So even if you wrap all of your interfaces like this, the user still has to eventually know when to use auto&. So really, the user hasn't gained any safety, outside of your particular APIs.
Forcing the user to capture by reference is a three-step process.
First, make the returned thing non-copyable:
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
then create a little passthrough function that delivers references reliably:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
Then write your static init() function, returning decltype(auto):
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
Full demo:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
struct foo
{
//...
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
};
int main()
{
auto& b = foo::init();
// won't compile == safe
// auto b2 = foo::init();
}
Skypjack noted correctly that init() could be written just as correctly without notstd::as_reference():
static decltype(auto) init()
{
static bar b;
return (b);
}
The parentheses around the return (b) force the compiler to return a reference.
My problem with this approach is that c++ developers are often surprised to learn this, so it could be easily missed by a less experienced code maintainer.
My feeling is that return notstd::as_reference(b); explicitly expresses intent to code maintainers, much as std::move() does.
The best, most idiomatic, readable, unsurprising thing to do would be to =delete the copy constructor and copy assignment operator and just return a reference like everybody else.
But, seeing as you brought up smart pointers...
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
A raw pointer would be perfectly acceptable here. If you don't like that, you have a number of options following the "pointers" train of thought.
You could use a shared_ptr without dynamic memory, with a custom deleter:
struct foo {
static shared_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
Although the caller doesn't "share" ownership, it's not clear what ownership even means when the deleter is a no-op.
You could use a weak_ptr holding a reference to the object managed by the shared_ptr:
struct foo {
static weak_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
But considering the shared_ptr destructor is a no-op, this isn't really any different from the previous example, and it just imposes on the user an unnecessary call to .lock().
You could use a unique_ptr without dynamic memory, with a custom deleter:
struct noop_deleter { void operator()() const noexcept {} };
template <typename T> using singleton_ptr = std::unique_ptr<T, noop_deleter>;
struct foo {
static singleton_ptr<bar> init() { static bar b; return { &b, {} }; }
}
This has the benefit of not needing to manage a meaningless reference count, but again the semantic meaning is not a perfect fit: the caller does not assume unique ownership, whatever ownership really means.
In library fundamentals TS v2 you can use observer_ptr, which is just a raw pointer that expresses the intent to be non-owning:
struct foo {
static auto init() { static bar b; return experimental::observer_ptr{&b}; }
}
If you don't like any of these options, you can of course define your own smart pointer type.
In a future standard you may be able to define a "smart reference" that works like reference_wrapper without the .get() by utilising overloaded operator..
If you want to use singleton, use it correctly
class Singleton
{
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
Singleton(const Singleton&) = delete;
Singleton& operator =(const Singleton&) = delete;
private:
Singleton() { /*acquire*/ }
~Singleton() { /*Release*/ }
};
So you cannot create copy
auto instance = Singleton::getInstance(); // Fail
whereras you may use instance.
auto& instance = Singleton::getInstance(); // ok.
But if you want scoped RAII instead of singleton, you may do
struct Foo {
Foo() { std::cout << "acquire\n"; }
~Foo(){ std::cout << "release\n"; }
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
static Foo init() { return {}; }
};
With the usage
auto&& foo = Foo::init(); // ok.
And copy is still forbidden
auto foo = Foo::init(); // Fail.
Someone would make a typo in one day and then we may or may not notice it in so many code, although we all know we should use auto& instead of auto.
The most convenient but very dangerous solution is using a derived class, as it breaks the strict-aliasing rule.
struct foo
{
private:
//Make these ref wrapper private so that user can't use it directly.
template<class T>
class Pref : public T {
private:
//Make ctor private so that we can issue a compiler error when
//someone typo an auto.
Pref(const Pref&) = default;
Pref(Pref&&) = default;
Pref& operator=(const Pref&) = default;
Pref& operator=(Pref&&) = default;
};
public:
static Pref<bar>& init() {
static bar b;
return static_cast<Pref<bar>&>(b);
}
///....use Pref<bar>& as well as bar&.
};
Assume I have a non-copyable class with multiple constructors with like this
class Foo: boost::noncopyable
{
public:
Foo(std::string s) {...}; // construct one way
Foo(int i) {...}; // construct another way
}
Now, I want to construct an object, and choose which constructor to use at runtime:
I could do it with pointers like this:-
boost::shared_ptr<Foo> f;
if (condition)
f.reset(new Foo(myString));
else
f.reset(new Foo(myInteger));
// common code follows
f->doSomethingComplicated(...);
But that feels messy and slow. Is there an easy way to choose the constructor for the object without resorting to dynamic allocation?
Some more details : The Foo class above is simply to illustrate the problem.The actual class involved is Windows Gdiplus::Bitmap - http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85).aspx
You can do it with C++11 on stack, without placement new and without copy/move constructor/assignment available. Observe:
auto factory = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
};
Foo&& foo = factory();
foo.doSomethingComplicated();
The functor and the Foo instance will live happily on stack, no allocations made (except for copying string in Foo's constructor, probably). Foo will get its destructor called when it gets out of scope. Win.
When using uniform initialization to construct return value, no copy/move operation is involved. Note that returning myString (implicit conversion) or Foo(myString) would force compiler to check if object is copyable/moveable, even if such copy/move could be elided.
Edit: alternatively, this can be made even shorter, but bit more "magical":
Foo&& foo = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
}();
Edit: Pre-C++11, Visual Studio hacky solution:
VC doesn't seem to check whether object is copyable when resorting on implicit conversion constructors to return value from a function. So this is valid, even though it's against the standard:
Foo make_foo(bool condition, const std::string&s, int i)
{
if ( condition) {
return s;
} else {
return i;
}
}
Then just use it like that:
Foo& f = make_foo(condition, myString, myInteger);
Note that this is yet another VC hack, as according to standard temporary can't be assigned to a reference to a mutable object, i.e. it would need to be changed const Foo&, which would be quite limiting here.
Not saying that you should handle it this way, but it is possible.
You have a flaw in your design. The 'Foo' is delegating the type elision to the user of the class. Have a look at boost::any (http://www.boost.org/doc/libs/1_55_0/doc/html/any.html)
I think the best option that meets your requirements (not dynamically allocated, not-copyable, pre-C++11) would be to use the placement new.
See here for a short example.
boost::optional might also be an acceptable option for you (it basically just does this for you internally, as well as keeping track of whether the object has been initialized). The in-place construction is a bit messy though for optional imo.
Keep it small and simple, I'd say. If this is a very local problem, why not just repeat the call?
if (condition)
{
Foo f(myString);
f.doSomethingComplicated();
}
else
{
Foo f(myInt);
f.doSomethingComplicated();
}
If that does not prove feasible, wrap a Foo pointer (or smart pointer) in a new class.
class FooWrapper // copyable
{
private:
boost::shared_ptr<Foo> m_foo;
public:
FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
FooWrapper(int i) : m_foo(new Foo(i)) {}
void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};
FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
Using C++11 you can do:
Foo&& f = condition ? Foo{myInteger} : Foo{myString};
f.doSomethingComplicated();
By using an r-value reference you avoid the constness and still extend the lifetime of the temporary.
If you only need to construct a temporary object, I think you can bind it to a const reference using a ternary expression:
const Foo &f(condition ? Foo(myString) : Foo(myInteger));
f.doSomethingComplicated(...);
Is there a good way to return a value from a function in C++ where we guarantee that the copy constructor is not called? Either the return value optimization or the move constructor are fine. For example, with the following code
#include <iostream>
struct Foo {
private:
// Disallow the copy and default constructor as well as the assignment
// operator
Foo();
Foo(Foo const & foo);
Foo & operator = (Foo const & foo);
public:
// Store a little bit of data
int data;
Foo(int const & data_) : data(data_) { }
// Write a move constructor
Foo(Foo && foo) {
std::cout << "Move constructor" << std::endl;
data=foo.data;
}
};
// Write a function that creates and returns a Foo
Foo Bar() {
Foo foo(3);
return foo;
}
// See if we can mix things up
Foo Baz(int x) {
Foo foo2(2);
Foo foo3(3);
return x>2 ? foo2 : foo3;
}
int main() {
// This is using the return value optimization (RVO)
Foo foo1 = Bar();
std::cout << foo1.data << std::endl;
// This should make the RVO fail
Foo foo2 = Baz(3);
std::cout << foo2.data << std::endl;
}
We have a compiler error
$ make
g++ -std=c++11 test01.cpp -o test01
test01.cpp: In function 'Foo Baz(int)':
test01.cpp:10:5: error: 'Foo::Foo(const Foo&)' is private
test01.cpp:35:25: error: within this context
make: *** [all] Error 1
since the copy constructor is private. Now, if we modify the Baz function to
// See if we can mix things up
Foo Baz(int x) {
Foo foo2(2);
Foo foo3(3);
return std::move(x>2 ? foo2 : foo3);
}
we do in fact run correctly. However, this seems to preclude the RVO from being used ever. Is there a better way to structure these functions if we must guarantee that the copy constructor is not called?
From the C++ standard:
[class.copy]/31: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. ... This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
in a return statement in a function with a class return type, when the expression is the name of a
non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-
unqualified type as the function return type, the copy/move operation can be omitted by constructing
the automatic object directly into the function’s return value
Since x > 2 ? foo2 : foo3 is not the name of an automatic object, copy elision is not permitted.
Interestingly, your example is addressed in n1377:
With this language feature in place, move/copy elision, although still
important, is no longer critical. There are some functions where NRVO
is allowed, but can be exceedingly difficult to implement. For
example:
A
f(bool b)
{
A a1, a2;
// ...
return b ? a1 : a2;
}
It is somewhere between difficult and impossible to decide whether to
construct a1 or a2 in the caller's preferred location. Using A's move
constructor (instead of copy constructor) to send a1 or a2 back to the
caller is the best solution.
We could require that the author of operator+ explicitly request the
move semantics. But what would be the point? The current language
already allows for the elision of this copy, so the coder already can
not rely on destruction order of the local, nor can he rely on the
copy constructor being called. The auto-local is about to be
conceptually destructed anyway, so it is very "rvalue-like". The move
is not detectable except by measuring performance, or counting copies
(which may be elided anyway).
Note that this language addition permits movable, but non-copyable
objects (such as move_ptr) to be returned by value, since a move
constructor is found and used (or elided) instead of the inaccessible
copy constructor.
Their example of solving this (in favor of move semantics) is:
// Or just call std::move
// return x>2 ? static_cast<Foo&&>(foo2) : static_cast<Foo&&>(foo3);
return static_cast<Foo&&>(x>2 ? foo2 : foo3);
The logic resulting from this implicit cast results in an automatic
hierarchy of "move semantics" from best to worst:
If you can elide the move/copy, do so (by present language rules)
Else if there is a move constructor, use it
Else if there is a copy constructor, use it
Else the program is ill formed
Or as Xeo mentions, you can structure it this way:
Foo Baz(int x) {
Foo foo2(2);
Foo foo3(3);
if (x > 2)
return foo2;
else
return foo3;
}
You already provided an example in the OP, but the standard provides one for eliding the move/copy constructor (it equally applies):
class Thing {
public:
Thing() { }
~Thing() { }
Thing(Thing&& thing) {
std::cout << "hi there";
}
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
// does not print "hi there"
But if you supply both the move and copy constructor, the move constructor seems to be preferred.
In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
Here is how it can work
A f() {
return { 10 };
}
This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!
To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.
As of the deleted copy/move constructors §8.4.3/2 states that
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:
struct A
{
A(int x) {}
A(A&&);
private:
A(A const&);
};
A f() {
return A(10); // Ok!
}
I was wondering, was this restriction lifted in C++11?
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
I remember it could be useful to allow callers of a function use the returned object, but that they are not able to copy the value and store it somewhere.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved. std::unique_ptr does this.
You can return a unique_ptr by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a function g as such:
std::unique_ptr<SomeType> g() {...}
You can do this:
std::unique_ptr<SomeType> value = g();
But not this:
std::unique_ptr<SomeType> value1 = g();
std::unique_ptr<SomeType> value2 = g();
value1 = value 2;
But this is possible:
std::unique_ptr<SomeType> value = g();
value = g();
The second line invokes the move assignment operator on value. It will delete the old pointer and move the new pointer into it, leaving the old value empty.
In this way, you can ensure that the contents of any unique_ptr is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers to unique_ptr or whatever), but there will be at most one location in memory where the actual pointer is stored.
Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
template<typename T>
struct ReturnProxy {
//This could be made private, provided appropriate frienship is granted
ReturnProxy(T* p_) : p(p_) { }
ReturnProxy(ReturnProxy&&) = default;
private:
//don't want these Proxies sticking around...
ReturnProxy(const ReturnProxy&) = delete;
void operator =(const ReturnProxy&) = delete;
void operator =(ReturnProxy&&) = delete;
struct SUPER_FRIENDS { typedef T GO; };
friend struct SUPER_FRIENDS::GO;
unique_ptr<T> p;
};
struct Object {
Object() : data(0) { }
//Pseudo-copy constructor
Object(ReturnProxy<Object>&& proxy)
: data(proxy.p ? proxy.p->data : throw "Don't get sneaky with me \\glare")
{
//steals `proxy.p` so that there isn't a second copy of this object floating around
//shouldn't be necessary, but some men just want to watch the world burn.
unique_ptr<Object> thief(std::move(proxy.p));
}
private:
int data;
Object(const Object&) = delete;
void operator =(const Object&) = delete;
};
ReturnProxy<Object> func() {
return ReturnProxy(new Object);
}
int main() {
Object o(func());
}
You could probably do the same in 03, though, using auto_ptrs. And it obviously doesn't prevent storage of the resultant Object, although it does limit you to one copy per instance.