std::make_shared, std::unique_ptr and move constructors - c++

The following code compiles with clang 3.0/libc++:
#include <memory>
class Foo
{
public:
Foo()
: mem_(new int(10))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>();
return 0;
}
But this one doesn't (std::string parameter added):
#include <memory>
#include <string>
class Foo
{
public:
Foo(const std::string& s)
: mem_(new int(10))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>("aaa");
return 0;
}
Clang complains about the usage of a deleted constructor. To me, this makes no sense, since std::make_shared isn't supposed to copy the Foo instance, the only thing that would trigger the call to the (deleted) copy constructor of std::unique_ptr.
But lo and behold, as soon as I define a move constructor explicitly, it compiles.
#include <memory>
#include <string>
class Foo
{
public:
Foo(const std::string& s)
: mem_(new int(10))
{
}
Foo(Foo&& other)
: mem_(std::move(other.mem_))
{
}
std::unique_ptr<int> mem_;
};
int main()
{
auto foo = std::make_shared<Foo>("aaa");
return 0;
}
Now, questions:
Why does it compile in the first example but not the second?
Can std::make_shared copy/move the object while constructing it?
Why does adding a move constructor fix the problem? I don't recall that adding non-default constructor should suppress an implicit move constructor.
EDIT: Checked and all examples appear to compile fine with gcc 4.5.1 (via ideone.com), I suspect it's the case of a clang/libc++ bug, but questions 2 and 3 still stand, plus I'd like to know which compiler is more "correct".

Why does it compile in the first example but not the second?
This is a libc++ bug. I am working on a fix for it now...
Can std::make_shared copy/move the object while constructing it?
No, I don't believe it can.
Why does adding a move constructor fix the problem? I don't recall
that adding non-default constructor should suppress an implicit move
constructor.
In the version of clang you're using, implicit move constructors are not implemented yet.
Update
Fixed: http://llvm.org/bugs/show_bug.cgi?id=11616

Related

Why doesn't the copy constructor work when I return an automatic variable from function?

In the below example I want to find out why the copy constructor isn't called when I return an automatic variable from the doit() function. I understand that the first version of handler is called because we have a temporary object but can't figure out why the copy constructor isn't called while creating that temporary object (copies everything from s to a temporary object).
#include <iostream>
using namespace std;
class S{
public:
S(){std::cout<<"Constructor\n";}
S(const S& s){std::cout<<"Copy Constructor\n";}
~S(){std::cout<<"Destructor\n";}
};
S doit(){
S s;
return s;
}
void handler(S&& r){
std::cout<<"Here\n";
}
void handler(const S& r){
std::cout<<"Here2\n";
}
int main() {
handler(doit());
}
Actually, there is a constructor being called in your code according to the rules of the language. However, the compiler has optimized that out and so you don't see the call. If you compile with -fno-elide-constructors you should see the copy-constructor being invoked.
Note that the copy-constructor will only be invoked because the defaulted move-constructor is suppressed. If you add that back like this:
S(S&&) = default;
then this move-constructor will be called instead. Here's a demo.

Adding dummy copy constructor to std::packaged_task

I'm trying to bypass std::packaged_task's lack of a copy constructor so that I can pass it into a std::function (which will only ever be moved).
I inherited from std::packaged_task and added a dummy copy constructor, which I assume shouldn't be called if I never copy the std::function it's moved into.
#include <iostream>
#include <future>
#include <functional>
#include <thread>
template <typename T>
class MyPackagedTask : public std::packaged_task<T()> {
public:
template <typename F>
explicit MyPackagedTask(F&& f)
: std::packaged_task<T()>(std::forward<F>(f)) {}
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(std::move(other)) {}
MyPackagedTask(const MyPackagedTask& other) {
// Adding this borks the compile
}
};
int main()
{
MyPackagedTask<int> task([]() {return 0;});
auto future = task.get_future();
std::thread t(std::move(task));
t.join();
std::cout << future.get() << std::endl;
}
Compiling this with gcc 6.2.1 I get the following error message (just the end part, let me know if you want the whole thing...):
/usr/include/c++/6.2.1/future:1325:6: error: invalid use of void expression
(*_M_result)->_M_set((*_M_fn)());
The error message was unparseable to me, so I was wondering if I'm doing something wrong or if the compiler is failing.
The move constructor definition is not correct, it forwards std::packaged_task<T()>&& as MyPackagedTask&& and that invokes a wrong constructor of std::packaged_task<T()>. This is the cause of the compiler error you observe.
The correct one:
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(static_cast<std::packaged_task<T()>&&>(other))
{}
In there static_cast<std::packaged_task<T()>&&>(other) does both the upcast to the base class and std::move.

What is the GCC option for disabling assignment operator optimizations

Let's start with this small example:
#include <vector>
#include <iostream>
using namespace std;
class A {
private:
A& operator =(const A&);
};
int main(void) {
vector<A> v;
v = { A() };
return 0;
}
Compilation of this code fails with the error message error: ‘A& A::operator=(const A&)’ is private. I have no idea why it needs the assignment operator so I tried to find out and changed the code to this:
#include <vector>
#include <iostream>
using namespace std;
class A {
public:
A& operator =(const A& a) { cout << "operator=" << endl; return *this; }
};
int main(void) {
vector<A> v;
v = { A() };
return 0;
}
Now the code compiles but when I execute it it does not output the debug message in the assignment operator implementation.
So the compiler wants the assignment operator but doesn't use it? I guess the compiler optimizes the assignment away somehow. Just like it optimizes the usage of move constructors (Which can be prevented with the option -no-elide-constructors). Is there a compiler option which can prevent assignment optimimzations? Or is there a different explanation why the compiler wants to have an accessible assignment operator but doesn't use it during runtime?
In C++03, types being stored in a container need to be CopyConstructible and Assignable. In C++11, requirements are relaxed and applied to the operations performed on the container.
class A needs to be CopyConstructible and Assignable because being stored in vector That's why you need public operator=
int main(void) {
vector<A> v;
v = { A() }; // Copy Constructor
A x;
x = v[0]; // operator=
return 0;
}
I little bit late but I still want to answer your question.
Your example shows a standard copy elision of C++. This is also discussed in another question.
That is, the compiler checks the correctness of your operation. You have to call a copy constructor right after default constructor to use vector and put your class inside, but call the default constructor only in order to improve performance.
C++ 11 solves the issue with the move constructor.

difference between ctor{} and {} when returning non-movable, non-copyable object

Here is the situation I came up with:
#include <iostream>
using namespace std;
struct test {
test() { cout << "ctor" << endl; }
test(const test&) = delete;
test(test&&) = delete;
};
auto f() -> test {
return {};
// return test{};
}
auto main() -> int {
f();
}
This code compiles with both clang and gcc, but when I change return {} to return test{} it doesn't compile anymore. Why is that? Shouldn't it work the same in both cases?
Frankly, I don't know if there is a good use case for this, but it caught me by surprise, so now I'm wondering what's going on.
return {} uses an empty initialiser list to initialise the return value, using the default constructor.
return test{} creates a temporary using the default constructor, then uses that to initialise the return value using a move or copy constructor. You have deleted those constructors, so that can't be done.
In practice, the copy or move will be elided so that both have the same effect - but the second still requires an accessible constructor, even if it's not actually used.
As an extension of Mike's answer:
int main()
{
// Error: Call to deleted move constructor (in C++98 the compiler would
// shout at the private copy constructor).
// auto t = test{};
// OK: Default constructor used
test t2;
test t3{};
return 0;
}
Even though the move/copy is elided, the C++ standard requires visibility of these constructors.

How to guarantee only one construction of an object returned by value?

I'm trying to implement a class, say Foo, which follows RAII, and objects of the class are returned to the client by value, i.e.
class SomeClass {
public:
class Foo {
public:
~Foo() { /* follow raii */ }
private:
friend class SomeClass;
Foo() { /* follow raii */ }
};
Foo getFoo() { return Foo(); }
};
My immediate question would be is there any way to be sure that only one object of type Foo is constructed when calling SomeClass::getFoo()? I would think that most compilers know only one object need be constructed, but I know this is not guaranteed in most cases. Is there a better approach I can take?
I've tried returning a boost::shared_ptr<Foo> and just allocating a Foo object when constructing the shared pointer, and this works nicely. However, it does not seem ideal, as it requires heap allocation and makes for a less-clean interface.
Thanks!
Clarification
Visual Studio 2005 compiler so I don't think R-val references and C++11 related features are available.
You've taken the best approach. The copy (or in fact move in C++11) will almost surely be elided by the compiler. In fact, even the copy from the return value to some object in the calling code will probably be elided too. So this will only call a single constructor:
Foo foo = sc.getFoo();
The rule that allows both of these copies (or moves) to be elided is:
when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
boost::optional + boost::in_place
If copy constructor is dangerous, it is better to disable it completely.
Though most of compilers would elide copies in your case, some times it is possible to disable copy elision, for instance -fno-elide-constructors - and if code which "believes" in copy-elision would happen to run on such settings - there may be fireworks.
In C++98 you may use boost::optional + boost::in_place - there is no heap allocation, becuase boost::optional reserves enough place. And it is guaranteed that there will be no any copies.
live demo
#include <boost/utility/in_place_factory.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <ostream>
using namespace boost;
using namespace std;
struct Foo: private noncopyable
{
explicit Foo(int i)
{
cout << "construction i=" << i << endl;
}
};
void make(optional<Foo> &foo)
{
foo = in_place(11);
}
int main()
{
optional<Foo> foo;
cout << "*" << endl;
make(foo);
cout << "!" << endl;
}
Output is:
*
construction i=11
!
This code does work on MSVC2005.
Boost.Move
Another option is to use move semantic emulation for C++98 - Boost.Move. Copies are disabled:
live demo
#include <boost/move/utility.hpp>
#include <iostream>
#include <ostream>
using namespace std;
class Movable
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
bool own_resource;
public:
Movable()
: own_resource(true)
{}
~Movable()
{
cout << (own_resource ? "owner" : "empty") << endl;
}
Movable(BOOST_RV_REF(Movable) x)
: own_resource(x.own_resource)
{
x.own_resource = false;
}
Movable& operator=(BOOST_RV_REF(Movable) x)
{
own_resource = x.own_resource;
x.own_resource = false;
return *this;
}
};
Movable make()
{
return Movable();
}
int main()
{
Movable m = make();
}
Output is:
empty
empty
owner
This code also does work on MSVC2005.
C++11
In C++11 use following approach:
live demo
struct Foo
{
Foo(const Foo &)=delete;
Foo(Foo &&)=delete;
Foo &operator=(const Foo&)=delete;
Foo &operator=(Foo &&)=delete;
Foo(int){}
};
Foo create()
{
//return Foo{0}; // ERROR: needs Foo(self &&)
return {0};
}
int main()
{
auto &&t=create();
}
Foo is created only once, it's copy and move constructor are deleted - it is guaranteed that there will be no any copies or moves.