SOLVED! See below
So, I'm trying to learn C++11 by doing some simple data structures and playing around with them. I did something similar to the following BST example using raw pointers and new and delete and it worked fine. Then I wanted to do it in a way that was more leak-safe.
// tree.cpp
//
//
#include <iostream>
#include <memory>
/* DECLARATIONS */
template <typename T>
struct Tree {
// members
T data;
std::unique_ptr<Tree<T> > left;
std::unique_ptr<Tree<T> > right;
// methods
Tree (T arg);
~Tree () = default;
void insert (Tree<T> child);
void insert (T arg);
void print (void);
};
template <typename T>
Tree<T>::Tree (T arg) {
data = arg;
left = nullptr;
right = nullptr;
}
template <typename T>
void Tree<T>::insert (Tree<T> child) {
if (child.data < data) {
if (left) {
left->insert(child);
} else {
left = &child;
}
} else {
if (right) {
right->insert(child);
} else {
right = &child;
}
}
}
template <typename T>
void Tree<T>::insert (T arg) {
Tree<T> child (arg);
this->insert(child);
}
template <typename T>
void Tree<T>::print (void) {
if (left) {
left->print();
}
std::cout << data;
if (right) {
right->print();
}
}
int main (void) {
Tree<int> root (0);
root.insert(3);
root.insert(-3);
root.insert(-2);
root.insert(2);
root.insert(11);
root.print();
return 0;
}
I don't undersatnd the error I'm getting from clang++, however.
$ clang++ -std=c++11 tree.cpp
tree_new.cpp:50:16: error: call to deleted constructor of 'Tree<int>'
this->insert(child);
^~~~~
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert' requested here
root.insert(3);
^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
void insert (Tree<T> child);
^
tree_new.cpp:34:20: error: call to deleted constructor of 'Tree<int>'
left->insert(child);
^~~~~
tree_new.cpp:50:9: note: in instantiation of member function 'Tree<int>::insert'requested here
this->insert(child);
^
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert' requested here
root.insert(3);
^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
void insert (Tree<T> child);
^
2 errors generated.
Why does it say I explicitly deleted the constructor when I declared the struct? I even defined a constructor explicitly! Also, any comments on scoping/ownership failure would be appreciated. I'm pretty sure this won't work the way I did it anyways.
Solution
The following link from MSDN clarified how one can use unique_ptrs.
Special thanks to BatchyX for his initial explanation of the problem (using a unique_ptr as a member implicitly (though the compiler says "explicitly"...) deletes the copy constructor for the class), and for noting that indeed Tree is still movable.
Something mentioned in that MSDN article is that std::move() returns an rvalue of its argument.
Here is the suitably modified code (excluding the obviously modified declarations). Note that there might be some optimizations possible still by using std::forward, but this at least seems to compile and run correctly.
template <typename T>
void Tree<T>::insert (std::unique_ptr<Tree<T> >&& pchild) {
if (pchild->data < data) {
if (left) {
// recurse, but must match on the rvalue signature
left->insert(std::move(pchild));
} else {
// invokes the move constructor for left instead of its copy constructor
left = std::move(pchild);
}
} else {
if (right) {
right->insert(std::move(pchild));
} else {
right = std::move(pchild);
}
}
}
template <typename T>
void Tree<T>::insert (T arg) {
// what is inside the insert(...) is an rvalue.
this->insert(std::unique_ptr<Tree<T> >(new Tree<T> (arg)));
}
std::unique_ptr is not copyable, and any class that contains a unique_ptr is also not copyable, meaning struct Tree is not copyable. The argument to:
void Tree<T>::insert (Tree<T> child) {
is taking its argument by value. And:
template <typename T>
void Tree<T>::insert (T arg) {
Tree<T> child (arg);
this->insert(child);
}
requires the copy constructor. To correct this, make struct Tree moveable.
Note Tree is not moveable (in contrast to BatchyX's comment) due to the presence of:
~Tree () = default;
which is a user-declared destructor and from section 12.8 Copying and moving class objects (point 9) of the c++11 standard (draft n3337):
If the definition of a class X does not explicitly declare a move constructor,
one will be implicitly declared as defaulted if and only if
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
(I was uncertain about the implicit generation of the move members and asked this question to be certain). To make it moveable either:
remove the user-declared destructor, or
define a move constructor and move assignment operator
note: copy constructor of 'Tree' is implicitly deleted because field 'left' has a deleted copy constructor
std::unique_ptr doesn't have a copy-constructor
The compiler may not warn you on this (maybe you need to activate more warnings), but this will not work:
template <typename T>
void Tree<T>::insert (Tree<T> child) {
// ...
left = &child;;
}
This code takes the address of a temporary variable and stores it inside a unique_ptr. This is wrong. unique_ptr<A> is for storing pointers to objects that have been allocated with new. One of its purpose is to delete them on destruction so you don't have any memory leak.
Here, child is a temporary that will be destroyed when exiting the function. That mean left will contain a pointer pointing to whatever lies on the stack. This may lead to random corruptions, and ultimately crashes when your Tree object will be destroyed.
Even if child is a reference (rvalue or lvalue), you cannot assume that it has been allocated with new, because it may not be the case (In your code, it is never the case), and even if it is was, maybe the object is already managed elsewhere (e.g. in another unique_ptr) so you shouldn't mess with it.
What you want instead is to allocate memory for a Tree object and store it inside left:
left = new Tree<T>(child);
You still need to sort out the argument to insert which requires Tree to be copyable (hint: use a rvalue references instead: Tree<T>&& child), but this problem is even worse because your compiler cannot detect these kind of errors.
Your specialized constructor
Tree(T arg);
overrides the compiler-generated default-constructor. So you must include it on your own:
T() = default;
Related
I thought to myself that I don't need std::forward<T>(arg); in my function because I wasn't passing the argument on to another function, I was using it directly. However then I thought even if I use it directly, by for example assigning it, or using it as a constructor argument then those each are function calls, respectively to operator= and constructor, which is a function call:
template <typename element_T>
void push_back(element_t&& copy)
{
*_end = copy; // This calls operator=, which is a function
}
template <typename ... ConstructorArgs>
void emplace_back(ConstructorArgs&& ... args)
{
new (_end) element_t(args);
// Calls constructor, needs (std::forward<ConstructorArgs>(args)...) ?
}
Do I need the calls to std::forward in these cases?
An expression that is a name of a variable is always an lvalue. For example, in
1 template <typename T>
2 void push_back(T&& copy) {
3 *_end = copy;
4 }
copy in line 3 has the lvalue value category no matter what type is deduced for T. Depending on how operator= in line 3 is defined/overloaded, this might result in selecting a wrong overload or in wrong type deduction.
Consider the following simple example (that follows the Ted Lyngmo's example from the comments section):
struct A {
void operator=(const A&); // (1)
void operator=(A&&); // (2)
};
struct C {
template<class T>
void push_back(T&& copy) {
a = copy;
}
A a;
};
C{}.push_back(A{});
Which A's assignment operator will be invoked here? One might expect (2) because A{} is a prvalue, but the correct answer is (1), because copy is an lvalue, and lvalues can't bind to rvalue references.
If we change the assignment to
a = std::forward<T>(copy);
then the expression std::forward<T>(copy) will have the xvalue value category and the (2) assignment operator will be called, as expected.
Placement new follows the same reasoning.
Suppose you have the following class:
template<typename T>
class A
{
...
A (T const &t)
{
...
}
A (T &&t) noexcept
{
...
}
};
Now suppose I want to provide a default argument to one of these (i.e., = T{}). Which is more efficient/consistent to default, the copy or the move? Does it even matter? My gut says it doesn't matter performance wise, which leads me to think it would be more consistent to default the copy since you should not bind a temporary to an r-value.
Thoughts?
Those are not copy / move constructors, so you don't have to use a reference at all.
Assuming you have distinguished those cases to elide copying t if you can, just have one construtor
template<typename T>
class A
{
...
/* explicit ? */ A (T t = {})
{
...
}
};
Probably this has been asked and answered already, but I don't know what to search for.
Can move semantics be used for non-pointer data members, if the data members have move assignment operators defined?
Suppose I have a class M that defines M::operator=(M&&) like this:
template <class T>
class M
{
public:
M()
{
mem_M = new T;
}
M& operator=(M&& src)
{
if (this != &src)
{
mem_M = src.mem_M;
src.mem_M = nullptr;
}
return *this;
}
private:
T* mem_M;
};
Now obviously I can have a class C<T> like this, with a move constructor that makes no use of T's move assignment operator:
template <class T>
class C
{
public:
C ()
{
mem_C = new T;
}
C (C&& rhs)
{
mem_C = rhs.mem_C;
rhs.mem_C = nullptr;
}
private:
T* mem_C;
};
However, what if I wanted C<T>::mem_C to not be a pointer but an ordinary member, how would I deal with C<T>::mem_C in the move-functions? I can of course invoke the move assignment operator T::operator=(T&&) to move the filed mem_C from one instance to the other, but how do I properly reset the instance of C passed to C<T>::C(C&&)?
This at least looks wrong to me:
template <class T>
class C
{
public:
C ()
{
mem_C = T();
}
C (C<T>&& rhs)
{
mem_C = std::move(rhs.mem_C);
rhs.mem_C = T(); // ?? like this?
}
private:
T mem_C;
};
So, what is the standard compliant way to reset non-pointer data members in move functions?
The move assignment/constructors for the contained types must leave the objects in an "acceptable" state, whatever that means for that type. Nothing outside the type being moved should have any responsibility for maintaining the state of the object.
Also, you want to make sure you're calling move constructors of contained types in your parent move constructor, not the contained type's move assignment as you are in your example:
// move constructor calls move constructor of contained elements
C (C<T>&& rhs) : mem_c(std::move(rhs.mem_c))
{
// anything in here is using already-constructed data members
}
// move assignment calls move assignment of contained elements
C & operator=(C<T>&& rhs) {
mem_c = std::move(rhs.mem_c);
}
I have an untemplated functor object that I'm trying to store as a std::function inside another object. This object is really heavyweight, so it's marked as uncopyable, but it does have a move constructor. However, trying to construct a std::function, or assign it, from a temporary constructor fails.
Here is a minimal example to provoke the error.
// pretend this is a really heavyweight functor that can't be copied.
struct ExampleTest
{
int x;
int operator()(void) const {return x*2;}
ExampleTest( ) :x(0){}
ExampleTest( int a ) :x(a){}
// allow move
ExampleTest( ExampleTest &&other ) :x(other.x) {};
private: // disallow copy, assignment
ExampleTest( const ExampleTest &other );
void operator=( const ExampleTest &other );
};
// this sometimes stores really big functors and other times stores tiny lambdas.
struct ExampleContainer
{
ExampleContainer( int );
std::function<int(void)> funct;
};
/******** ERROR:
Compiler error: 'ExampleTest::ExampleTest' : cannot access private member
declared in class 'ExampleTest'
******************/
ExampleContainer::ExampleContainer( int x )
: funct( ExampleTest( x ) )
{}
/******** ERROR:
Compiler error: 'ExampleTest::ExampleTest' : cannot access private member
declared in class 'ExampleTest'
******************/
int SetExample( ExampleContainer *container )
{
container->funct = ExampleTest();
return container->funct();
}
In an even simpler construction, where I'm just making a local function, I also get the error:
int ContrivedExample( )
{
// extra parens to sidestep most vexing parse
std::function<int()> zug( (ExampleTest()) );
/*** ERROR: 'ExampleTest::ExampleTest' : cannot access private member
declared in class 'ExampleTest' */
int troz = zug( ) ;
return troz;
}
So far as I can tell, in all of these cases, a temporary ExampleTest ought to be passed to the function constructor as an rvalue. Yet the compiler wants to copy them.
What gives? Is it possible to pass uncopyable (but move-copyable) functor objects to a std::function constructor? There are workarounds with pointers and so on, but I want to understand what is going on here.
The specific errors above are from Visual Studio 2012 with the CTP C++11 patch. GCC 4.8 and Clang 3 also fall down, with their own error messages.
This object is really heavyweight, so it's marked as uncopyable, but it does have a move constructor.
If a functor is non-copyable, it does not meet the necessary requirements for being used with std::function. Paragraph 20.8.11.2.1/7 of the C++11 Standard specifies:
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes
and return type R. The copy constructor and destructor of A shall not throw exceptions.
std::function can be move-constructed from rvalue of a functor object. And most implementations do that.
The "my target must be copy-constructable" requirement of std::function is due to its own requirement of being copy-constructable. std::function's type is defined only by its target's signature(eg: void(int)) and std::function itself is defined by the standard to be copy-constructable. So when you copy-construct a std::function, it needs to call the copy-ctor of the its target(the underlying functor). So it requires its target having one. It has no other choices.
Having the requirement that the target being copy-constructable, the standard does not say that the implementations should copy, instead of move, when you construct a std::function from a rvalue callable object. The implemention will probably only call the move-ctor of your callable object.
More detailed additional information with examples and tests:
For example in gcc(MSVC is similar) implementation for the ctor of std::function from any callable object:
template<typename _Res, typename... _ArgTypes>
template<typename _Functor, typename>
function<_Res(_ArgTypes...)>::
function(_Functor __f)
: _Function_base()
{
typedef _Function_handler<_Signature_type, _Functor> _My_handler;
// don't need to care about details below, but when it uses __f, it
// either uses std::move, or passes it by references
if (_My_handler::_M_not_empty_function(__f))
{
_My_handler::_M_init_functor(_M_functor, std::move(__f));
_M_invoker = &_My_handler::_M_invoke;
_M_manager = &_My_handler::_M_manager;
}
}
passing by value of the argument of "_Functor __f" will use its move constructor if it has one, and it will use its copy constructor if it does not have a move ctor. As the following test program can demonstrate:
int main(){
using namespace std;
struct TFunctor
{
TFunctor() = default;
TFunctor(const TFunctor&) { cout << "cp ctor called" << endl; }
TFunctor(TFunctor&&) { cout << "mv ctor called" << endl; };
void operator()(){}
};
{ //!!!!COPY CTOR of TFunctor is NEVER called in this scope
TFunctor myFunctor;
//TFunctor move ctor called here
function<void()> myStdFuncTemp{ std::move(myFunctor) };
function<void()> myStdFunc{ move(myStdFuncTemp) };
}
{ //TFunctor copy ctor is called twice in this scope
TFunctor myFunctor;
//TFunctor copy ctor called once here
function<void()> myStdFuncTemp{ myFunctor };
//TFunctor copy ctor called once here
function<void()> myStdFunc{ myStdFuncTemp };
}
}
Finally, you could make a unstd::function_only_movable which has almost everything the same with std::function but deletes its own copy ctor so it does not need to require the target callable object to have one copy ctor. You also need to only construct it from rvalue of callable objects.
The print statement in the constructor's definition doesn't get printed, isn't the constructor calling correct in main? I know I am missing some point here, please point out.
#include <iostream>
#include <typeinfo>
template <typename T> class List
{
public:
template <typename T2> List (List<T2> const&);
};
template <typename T> template <typename T2> List <T> :: List (List <T2> const&)
{
std :: cout << "\nType name:" << typeid (T2).name();
}
int main ()
{
List <int> kk (List <int>);
return 0;
}
There are a couple of things wrong in your code that you might not be aware of.
List<int> kk( List<int> );
That line is not a variable definition, but rather the declaration of a function that takes a List<int> as argument and returns a List<int>, so that effectively will not call any constructor. That is know as the most-vexing-parse (you can look at different versions of it by searching in SO, or in the C++ FAQ lite)
The second issue is that you cannot possibly create any instance of the an instantiated type of List, the reason being is that the only constructor that you are providing is a templated constructor that takes a second List<U> as argument. That effectively disables the default constructor, so the only way of creating a List<T> is by already having a List<U>, and that is not possible. You can add the default constructor back:
template <typename T>
class List {
public:
List() {}
template <typename U>
List( List<U> const & ) {} // prefer const& as that will avoid unnecessary copying
};
And now you can write:
List<int> l = List<int>(); // this will call List<int>::List( List<int> const & )
And yet, that will still not call the constructor you want. The reason is a little obscure, but when copy constructing an element of a template, the compiler will not use a templated constructor. In the code above, it will implicitly define a copy constructor by doing member-wise copy constructor of the methods and call that generated constructor. That means that in most occasions where you want to provide a templated constructor you want to also provide a non-templated copy constructor.
To actually call that constructor you would have to provide a different type:
List<int> l = List<double>();
Since the types actually differ, the compiler cannot copy construct, will find that the provided templated constructor is the best overload candidate and call it.
As well as the "most vexing parse" identified by David:
you need to have at least one more constructor to create the original List object to be passed to the copy constructor,
you need to vary the parameter type in order to have the templated copy constructor invoked: as is you'll match the implicitly declared List(const List&) copy constructor instead.
So:
#include <iostream>
template <typename T>
struct X
{
X() { std::cout << "X()\n"; }
// implicitly like this anyway...
// X(const X& rhs) { std::cout << "X(X&)\n"; }
template <typename U>
X(const U& u) { std::cout << "U\n"; }
};
int main()
{
X<int> x;
X<int> y(x);
}
What are you trying to do with this statement:
List <int> kk (List <int>);
(It actually declares a function, and can't be anything but
a function declaration.)
In order to see output from the copy constructor, you've got to
invoke the copy constructor somehow. Which means having an
object to copy. Which isn't possible with the code you've
given: since you've explicitly declared a constructor, the
compiler will not provide a default constructor, and you have no
other constructor with which to create an object. So you have
no way of creating anything to copy. If you add a
List() {}
to the class, and write:
List<int> kk((List<int>());
, you might get something, but the compiler is allowed to elide
the copy here, so more likely there will be no output. Try:
List<int> a;
List<int> b(a);
Or just put your output in the default constructor.