Template functions: default construction without copy-constructing in C++ - c++

Considering
struct C {
C() { printf("C::C()\n" ); }
C(int) { printf("C::C(int)\n" ); }
C( const C& ) { printf("copy-constructed\n"); }
};
And a template function
template< typename T > void foo(){
// default-construct a temporary variable of type T
// this is what the question is about.
T t1; // will be uninitialized for e.g. int, float, ...
T t2 = T(); // will call default constructor, then copy constructor... :(
T t3(); // deception: this is a local function declaration :(
}
int main(){
foo<int>();
foo<C >();
}
Looking at t1, it will not be initialized when T is e.g. int. On the other hand, t2 will be copy-constructed from a default constructed temporary.
The question: is it possible in C++ to default-construct a generic variable, other than with template-fu?

Here's a trick you can use, using a local class:
template <typename T> void foo() {
struct THolder {
T obj;
THolder() : obj() { } // value-initialize obj
};
THolder t1; // t1.obj is value-initialized
}
I think I read about this trick from an answer to another Stack Overflow question, but I am unable to find that question at the moment.
Alternatively, you can use the boost::value_initialized<T> class template, which basically does the same thing, with greater flexibility and consistency and with workarounds for buggy compilers.
In C++0x, it's much easier: you can use an empty initializer list:
T obj{}; // obj is value-initialized
(To the best of my knowledge, only gcc 4.5+ supports C++0x initializer lists. Clang and Visual C++ don't yet support them.)

If you don’t care for the fact that the copy constructor must exist, and just want to prevent it being called:
Don’t worry: it won’t be. The copy constructor call will be elided in this situation. Always, and reliably – even when you compile with optimizations disabled (-O0).

What is your real question? The default constructor is called for t1 instance.

T t2 = T(); // will call default constructor, then copy constructor... :(
Not on my compiler (VC2008). Output for me is...
C::C()
C::C()
Which is what I'd expect it to do. Am I missing something?

Related

Perfect forwarding and constructors

I am trying to understand the interaction of perfect forwarding and constructors. My example is the following:
#include <utility>
#include <iostream>
template<typename A, typename B>
using disable_if_same_or_derived =
std::enable_if_t<
!std::is_base_of<
A,
std::remove_reference_t<B>
>::value
>;
template<class T>
class wrapper {
public:
// perfect forwarding ctor in order not to copy or move if unnecessary
template<
class T0,
class = disable_if_same_or_derived<wrapper,T0> // do not use this instead of the copy ctor
> explicit
wrapper(T0&& x)
: x(std::forward<T0>(x))
{}
private:
T x;
};
class trace {
public:
trace() {}
trace(const trace&) { std::cout << "copy ctor\n"; }
trace& operator=(const trace&) { std::cout << "copy assign\n"; return *this; }
trace(trace&&) { std::cout << "move ctor\n"; }
trace& operator=(trace&&) { std::cout << "move assign\n"; return *this; }
};
int main() {
trace t1;
wrapper<trace> w_1 {t1}; // prints "copy ctor": OK
trace t2;
wrapper<trace> w_2 {std::move(t2)}; // prints "move ctor": OK
wrapper<trace> w_3 {trace()}; // prints "move ctor": why?
}
I want my wrapper to have no overhead at all. In particular, when marshalling a temporary into the wrapper, as with w_3, I would expect the trace object to be created directly in place, without having to call the move ctor. However, there is a move ctor call, which makes me think a temporary is created and then moved from. Why is the move ctor called? How not to call it?
I would expect the trace object to be created directly in place,
without having to call the move ctor.
I don't know why you expect that. Forwarding does exactly this: moves or copies 1). In your example you create a temporary with trace() and then the forwarding moves it into x
If you want to construct a T object in place then you need to pass the arguments to the construction of T, not an T object to be moved or copied.
Create an in place constructor:
template <class... Args>
wrapper(std::in_place_t, Args&&... args)
:x{std::forward<Args>(args)...}
{}
And then call it like this:
wrapper<trace> w_3 {std::in_place};
// or if you need to construct an `trace` object with arguments;
wrapper<trace> w_3 {std::in_place, a1, a2, a3};
Addressing a comment from the OP on another answer:
#bolov Lets forget perfect forwarding for a minute. I think the
problem is that I want an object to be constructed at its final
destination. Now if it is not in the constructor, it is now garanteed
to happen with the garanteed copy/move elision (here move and copy are
almost the same). What I don't understand is why this would not be
possible in the constructor. My test case proves it does not happen
according to the current standard, but I don't think this should be
impossible to specify by the standard and implement by compilers. What
do I miss that is so special about the ctor?
There is absolutely nothing special about a ctor in this regard. You can see the exact same behavior with a simple free function:
template <class T>
auto simple_function(T&& a)
{
X x = std::forward<T>(a);
// ^ guaranteed copy or move (depending on what kind of argument is provided
}
auto test()
{
simple_function(X{});
}
The above example is similar with your OP. You can see simple_function as analog to your wrapper constructor and my local x variable as analog to your data member in wrapper. The mechanism is the same in this regard.
In order to understand why you can't construct the object directly in the local scope of simple_function (or as data member in your wrapper object in your case) you need to understand how guaranteed copy elision works in C++17 I recommend this excelent answer.
To sum up that answer: basically a prvalue expression doesn't materializez an object, instead it is something that can initialize an object. You hold on to the expression for as long as possible before you use it to initialize an object (thus avoiding some copy/moves). Refer to the linked answer for a more in-depth yet friendly explanation.
The moment your expression is used to initialize the parameter of simple_foo (or the parameter of your constructor) you are forced to materialize an object and lose your expression. From now on you don't have the original prvalue expression anymore, you have a created materialized object. And this object now needs to be moved into your final destination - my local x (or your data member x).
If we modify my example a bit we can see guaranteed copy elision at work:
auto simple_function(X a)
{
X x = a;
X x2 = std::move(a);
}
auto test()
{
simple_function(X{});
}
Without elision things would go like this:
X{} creates a temporary object as argument for simple_function. Lets call it Temp1
Temp1 is now moved (because it is a prvalue) into the parameter a of simple_function
a is copied (because a is an lvalue) into x
a is moved (because std::move casts a to an xvalue) to x2
Now with C++17 guaranteed copy elision
X{} no longer materializez an object on the spot. Instead the expression is held onto.
the parameter a of simple_function can now by initialized from the X{} expression. No copy or move involved nor required.
The rest is now the same:
a is copied into x1
a is moved into x2
What you need to understand: once you have named something, that something must exist. The surprisingly simple reason for that is that once you have a name for something you can reference it multiple times. See my answer on this other question. You have named the parameter of wrapper::wrapper. I have named the parameter of simple_function. That is the moment you lose your prvalue expression to initialize that named object.
If you want to use the C++17 guaranteed copy elision and you don't like the in-place method you need to avoid naming things :) You can do that with a lambda. The idiom I see most often, including in the standard, is the in-place way. Since I haven't seen the lambda way in the wild, I don't know if I would recommend it. Here it is anyway:
template<class T> class wrapper {
public:
template <class F>
wrapper(F initializer)
: x{initializer()}
{}
private:
T x;
};
auto test()
{
wrapper<X> w = [] { return X{};};
}
In C++17 this grantees no copies and/or moves and that it works even if X has deleted copy constructors and move constructors. The object will be constructed at it's final destination, just like you want.
1) I am talking about the forwarding idiom, when used properly. std::forward is just a cast.
A reference (either lvalue reference or rvalue reference) must be bound to an object, so when the reference parameter x is initialized, a temporary object is required to be materialized anyway. In this sense, perfect forwarding is not that "perfect".
Technically, to elide this move, the compiler must know both the initializer argument and the definition of the constructor. This is impossible because they may lie in different translation units.

default constructor in modern c++

When I run this code, the VS compiler return error and says that t1.mem is uninitialized local variable.
#include <string>
#include <iostream>
struct T1
{
int mem;
};
struct T2
{
int mem;
T2() { } // "mem" is not in the initializer list
};
int main()
{
T1 t1; // class, calls implicit default ctor
std::cout << t1.mem << std::endl;
const T2 t2; // const class, calls the user-provided default ctor
// t2.mem is default-initialized (to indeterminate value)
std::cout << t2.mem << std::endl;
}
If I have not assigned the constructor for struct T1, the compiler would have to generate the default constructor? And struct T2's constructor is empty initialization list, why it has no error tips?
My understanding is that the compiler is trying to protect you from its own generated code, and assumes "you know best" when using your provided constructor. In addition, checking whether or not your constructor actually ends up initializing T2.mem anywhere, including in the body of the constructor, could be an arbitrarily complex task, so the compiler authors may have decided that was a task better left unattempted than poorly executed.
This seems to be supported by the warning you would get from MSVC if you declared t1 as a const T1:
'const' automatic data initialized with compiler generated default constructor produces unreliable results
Note the wording "compiler generated default constructor".
Btw, you'll see this same warning if you request the compiler-generated default constructor with T2() = default.
Well, compilers aren't perfect. Sometimes they warn for one thing, but they don't for another, similar thing. Many compilers also offer runtime instrumentation of the generated code, where they insert special instructions that detect errors like use of uninitialized variables and will abort the program when that happens. But again, the system is not perfect and it can miss things.
In any event, you don't actually need a constructor. You can inline-initialize the class members:
struct T1
{
int mem = 0;
};
The inline initialization will be used by default, unless a constructor initializes the member to something else:
struct T1
{
int mem = 0;
T1() = default;
T1(int m) : mem(m) { }
};
// ...
T1 first; // first.mem == 0
T1 second(1); // second.mem == 1

Choosing constructor for a noncopyable object

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(...);

Should a type be move-only, just because copying may be expensive?

I have a type that is copyable, but may be expensive to copy. I have implemented the move constructor and move assignment. But I have performance issues where folks forget to call move() when passing by value.
Is it good C++11 style to remove the copy constructor, and instead provide an explicit copy() method for the rare cases when a copy is actually desired? This is idiomatic in other languages (Ruby, JavaScript) but I don't know of anything in the C++ standard library that prohibits copy purely for performance. For instance, std::vector<> is copyable, while std::unique_ptr<> and std::thread are non copyable for other reasons.
Should a type be move-only, just because copying may be expensive?
No. If the semantics of your type is such that copying it is conceptually meaningful, then the correct way to make copying available is to implement a copy constructor, and give the user a chance to adopt standard syntax for invoking it:
T a;
T a = b;
If people will forget to move from objects they don't want to use anymore... Well, that's their bad:
T c = std::move(a); // I'm doing it right (if I no longer need object a);
T d = b; // If I don't need b anymore, I'm doing it wrong.
And if (for any reason) for some functions of yours it is always desirable that the caller provides an object from which it is possible to move, then let the function accept an rvalue reference:
void foo(my_class&& obj);
my_class a;
foo(a); // ERROR!
foo(std::move(a)); // OK
I would treat the class as non-copyable in signature if copy is sufficiently expensive. Semantically things are copyable only if you want them to be, and an expensive copy is a decent reason to decide "no, not copyable".
The ability for something to be copied does not mean it need be implemented in a type that is copyable. The implementer of that type gets to decide if it should be semantically copyable.
I wouldn't call the operation that produced an expensive copy "copy", but rather "clone" or "duplicate".
For a way you might do this:
#include <utility>
template<typename T>
struct DoCopy {
T const& t;
DoCopy( T const& t_ ):t(t_) {}
};
template<typename T>
DoCopy<T> do_copy( T const& t ) {
return t;
}
struct Foo {
struct ExpensiveToCopy {
int _[100000000];
};
ExpensiveToCopy* data;
Foo():data(new ExpensiveToCopy()) {}
~Foo(){ delete data; }
Foo(Foo&& o):data(o.data) { o.data = nullptr; }
Foo& operator=(Foo&& o) { data=o.data; o.data=nullptr; return *this; }
Foo& operator=(DoCopy<Foo> o) {
delete data;
if (o.t.data) {
data=new ExpensiveToCopy(*o.t.data);
} else {
data=new ExpensiveToCopy();
}
return *this;
}
Foo( DoCopy<Foo> cp ):data(cp.t.data?new ExpensiveToCopy( *cp.t.data ):new ExpensiveToCopy() ) {};
};
int main() {
Foo one;
// Foo two = one; // illegal
Foo three = std::move(one); // legal
Foo four;
Foo five = do_copy(three);
four = std::move(three);
five = do_copy(four);
}
This is somewhat similar to the ways you could have written std::move like semantics prior to the existence of rvalue references, with similar downsides to such techniques, namely that the language itself has no idea what shenanigans you are up to.
It has the advantage that the syntax of the above do_copy is similar to the syntax of std::move, and it allows you to use traditional expressions without having to create trivial instances of Foo then construct a copy of another variable etc.
If the situations where we want to treat it as copyable are common (if to be avoided), I'd write a copy-wrapper around the class that knows about the duplicate method.
No. If the type is copyable then the type is copyable. This means its copy constructor is available and works. It doesn't mean there's some member function whose name looks like the characters c, o, p and y in sequence, that does "sort of nearly a similar thing".

Why auto v {create()}; does not compile?

i was doing some tests of the move semantics and I tried this :
class A{
public:
A(){printf("A CTOR\n");}
A(A&) {printf("A CTOR by copy\n");}
A(A&&){printf("A CTOR by universal reverence\n");}
};
A&& create(){
A v;
return std::move(v);
}
auto x{ create() };//this does not compile
float d[]{1.2,1.3,5,6};//this does compile
I get the following error:
error C3086: cannot find 'std::initializer_list': you need to #include <initializer_list>
I don't understand as the initializer list feature has been added to VC11 with CTP2012 nov.
Is this because we have to wait for an update of the stdlib ?
I think the code is correct as I copied it from a slide from Scott meyers: Move Semantics, Rvalue References, Perfect Forwarding.
Thank you for your help.
For your information, the spurious copies occured because i did not add "const" in my CTOR by copy.
Best
Braces with auto will always end up in std::initializer_list<T> type. So basically what happens here you try to create a std::initializer_list<A> here for x instead of A what probably was your intent here. However your code should compile fine and that may be a bug in the VS latest CTP compiler.
To make x be of A you have 2 options:
Do not use auto here:
A x{ create() };
Do not use Uniform initialization here:
auto x(create());
Beside that I see 2 other issues in you code. Firstly signature of proper copy-constructor should look like that:
A(const A &) {printf("A CTOR by copy\n");}
Moreover it is not encouraged to return RValue references from functions. Instead you should return by value like that:
A create(){
A v;
return v; // std::move not needed here because C++11 compiler will put it for you here
}
or just:
A create(){
return A();
}
EDIT:
Oh and just to be politically correct A(A&&) is not "A CTOR by universal reference". It is "A CTOR by move" or "A CTOR by rvalue reference" depending on which level of abstraction you want to operate. Universal reference is always about templates and that specific type type deduction.
Please also read an article of Scott Meyers I attached in a different comment http://scottmeyers.blogspot.com/2012/10/copying-constructors-in-c11.html where the same C++ guru that you refer in your notes exactly explains the problems you face. Hope that helps.
The line
auto x{ create() };//this does not compile
creates an initializer_list and not an instance of A, see for example std::initializer_list.
If you write
A x{ create() };
the code compiles and the type of x will be A.
I wouldn't return A&& from create(), see Move Semantics and Compiler Optimizations. I haven't seen this in Scott's slides either.
The following code prints only A CTOR, see here. That is the best you can get: The object has to be created. Apart from that there are no unnecessary copy constructor or assignment operator calls.
#include <cstdio>
#include <utility>
using namespace std;
class A{
public:
A(){ printf("A CTOR\n");}
A(const A&) {printf("A CTOR by copy\n");}
A(A&&){ printf("A CTOR by universal reverence\n");}
A& operator=(const A& ) = delete;
};
A create(){
return A();
}
int main() {
A x{ create() };
return 0;
}
std::move is not the only way to get rid of the unnecessary copies. The compiler can do it for you, see for example What are copy elision and return value optimization? or Copy elision.