Move ctor is not called - c++

Am I doing something wrong (again)?
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map& pattern)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&& tmp)\n";
}
};
Map createMap()
{
return Map();
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2(Map(m1));//<<I thought that I create here tmp unnamed obj.
Map m3(createMap());//<<---or at least here, but nope...
return 0;
}
Please see the commented line in the code
Edited [taken from FredOverflow answer]
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2((Map(m1)));
std::cout << "\nmove\n";
Map m3(createMap());
}
I'm getting output:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)//Here why not move ctor aswell as copy?
move
Map()
Map()
Map(Map&& tmp)

Map m3(createMap());//<<---or at least here, but nope...
You are seeing return value optimization in action. In C++, the compiler is allowed to optimize away copying returned objects, and let the function work directly with the caller's object where the result is stored. There isn't any need to invoke the move constructor either.
Make the function more complicated, so that the compiler cannot use the optimization, and you'll see moving in action. For example:
Map createMap()
{
Map a, b;
if (rand())
return a;
return b;
}

You're declaring a function, not an object:
T name (T(blah));
Is equivalent to:
T name(T blah);
Which is recognizable as a function declaration. You can use extra parens:
Map m2 ((Map(m1)));
This is called the most vexing parse.

I slightly modified your main routine to understand the output better:
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2(Map(m1));
std::cout << "\nmove\n";
Map m3(createMap());
}
And here is the output with g++ -fno-elide-constructors:
default
Map()
copy
Map(const Map& pattern)
move
move
Map()
Map(Map&& tmp)
Map(Map&& tmp)
As others already pointed out, Map m2(Map(m1)); is indeed a function declaration, so you get no output. The second move is not interpreted as a function declaration, because createMap is not a type name. There are two move constructors involved here. One moves the temporary object created by evaluating Map() into the temporary object created by evaluating createMap(), and the second move initializes m3 from the latter. This is exactly what one would expect.
If you fix the first move by writing Map m2((Map(m1))); the output becomes:
move
Map(const Map& pattern)
Map(Map&& tmp)
Again, no surprises. The copy constructor is invoked by evaluating Map(m1), and that temporary object is then moved into m2. If you compile without -fno-elide-constructors, the move operations disappear, because they are replaced by even more efficient optimizations like RVO or NRVO:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)
move
Map()
I'm sure Visual C++ has a compiler option similar to -fno-elide-constructors that you can play with to understand move semantics better.

This program shows expected output.
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map&)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&&)\n";
}
};
Map createMap()
{
Map m;
return m;
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2 = createMap();//<<I thought that I create here tmp unnamed obj.
std::cin.get();
return 0;
}
Note the changes to createMap(). It doesn't employ a direct temporary but a named return value. This program shows the intended output on Visual Studio 2010.

Map createMap()
{
return Map();
}
I would think that the compiler would've done an RVO (return value optimization) on the above, thus no temporaries would ever be created.
If you change it to the following, you should see your move ctor getting invoked.
Map createMap()
{
Map m;
m.DoSomething(); // this should make the compiler stop doing RVO
return m;
}
Some compilers do RVO regardless of compiler settings (debug / release mode) - e.g. bcc32. I have a feeling VC would be the same.

Related

Should I change this code that uses push_back to use std::move?

I have just read about the rvalue references and below is the code I am referring to
vector<string> v;
string s = "hello";
v.push_back(s);
cout << s << endl;
cout << v[0] << endl;
return 0
My question is that till now, whenever I have seen vector of objects (or strings), I mostly see inserts being done like above. Instead if I did v.push_back(std::move(s)) then I am not unnecessarily creating duplicate objects.
Should this be the correct way of adding objects to STL where all we care about is the data in container and not otherwise variables.
Given the comments I've gotten, I've decided on a different approach to this answer. Here is a program that uses various ways of adding an object to a vector. This program prints out exactly which copy constructors, move constructors, copy operators, move operators, and destructors are called in all cases.
The program uses the marvelous fmt library. And fmt::print does exactly what you think it does. I should, perhaps, use ::fmt. Keep in mind that moving from an object leaves it in an unspecified (note, not the same as undefined) state, in general. Of course, for classes you write yourself, you know exactly what state it's in. But for standard library classes, or classes written by other people, you don't. Apparently, for the standard library classes you are guaranteed that if you do something to set the state to something known, that the object will indeed change to that state.
Personally, I would just treat the object as if the only valid operation on it after you move from it is to call its destructor. But I can see cases in which you might simply want to re-use the storage in some way.
Here is the program:
#include <fmt/core.h> // fmt
#include <vector> // vector
#include <utility> // move
class TestClass {
public:
TestClass(int a, int b) {
fmt::print("TestClass{{{}, {}}}\n", a, b);
}
TestClass(TestClass const &) noexcept {
fmt::print("TestClass{{TestClass const &}}\n");
}
TestClass(TestClass &&) noexcept {
fmt::print("TestClass{{TestClass &&}}\n");
}
TestClass const &operator =(TestClass const &) noexcept {
fmt::print("=(TestClass const &)\n");
return *this;
}
TestClass const &operator =(TestClass &&) noexcept {
fmt::print("=(TestClass &&)\n");
return *this;
}
~TestClass() noexcept {
fmt::print("~TestClass()\n");
}
};
int main()
{
::std::vector<TestClass> v;
// Reserve necessary space so movements of vector elements doesn't clutter up
// the output.
v.reserve(6);
fmt::print("Constructing initial\n");
TestClass o{1, 2};
fmt::print("\bv.push_back(o)\n");
v.push_back(o);
fmt::print("\nv.push_back(::std::move(o))\n");
v.push_back(::std::move(o));
fmt::print("\nv.push_back(TestClass{{3, 4}})\n");
v.push_back(TestClass{3, 4});
fmt::print("\nv.emplace_back(5, 6)\n");
v.emplace_back(5, 6);
fmt::print("\nv.emplace_back(::std::move(o))\n");
v.emplace_back(::std::move(o));
fmt::print("\nv.emplace_back(TestClass{{5, 6}})\n");
v.emplace_back(TestClass{5, 6});
fmt::print("\nHere H\n");
}
Here is the program's output:
Constructing initial
TestClass{1, 2}
v.push_back(o)
TestClass{TestClass const &}
v.push_back(::std::move(o))
TestClass{TestClass &&}
v.push_back(TestClass{3, 4})
TestClass{3, 4}
TestClass{TestClass &&}
~TestClass()
v.emplace_back(5, 6)
TestClass{5, 6}
v.emplace_back(::std::move(o))
TestClass{TestClass &&}
v.emplace_back(TestClass{5, 6})
TestClass{5, 6}
TestClass{TestClass &&}
~TestClass()
Here H
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()
~TestClass()
I will say that this program has exactly the output I expected, and that output is (AFAIK) consistent with the answer I had here before.
Why I use ::std:: instead of std::
Q: What should be used?
//emplace_back constructs the elements in place.
emplace_back("element");
//push_back will create new object and then copy(or move) its value of arguments.
push_back(explicitDataType{"element"});
So here you should use emplace_back() instead of std::move().

Vector of non-const objects seems to be treated as constant in range-based for loop

I have a std::vector of objects being filled by de-referencing std::unique_ptr's in the push_back calls. However, when I run through a mutable range-based for-loop, my modification to these objects stays local to the loop. In other words, it seems as those objects are being treated as constant, despite that lack of a const keyword in the loop. Here is minimal code to demonstrate what I'm seeing:
#include <vector>
#include <memory>
#include <iostream>
class Item
{
public:
typedef std::unique_ptr<Item> unique_ptr;
inline static Item::unique_ptr createItem()
{
return std::unique_ptr<Item>(new Item());
}
inline const int getValue() const { return _value; }
inline void setValue(const int val) { _value = val; }
private:
int _value;
};
int main()
{
std::vector<Item> _my_vec;
for (int i = 0; i < 5; i++)
{
Item::unique_ptr item = Item::createItem();
_my_vec.push_back(*item);
}
for (auto item : _my_vec)
{
// modify item (default value was 0)
item.setValue(10);
// Correctly prints 10
std::cout << item.getValue() << std::endl;
}
for (auto item : _my_vec)
{
// Incorrectly prints 0's (default value)
std::cout << item.getValue() << std::endl;
}
}
I suspect this has something to do with the move semantics of std::unique_ptr? But that wouldn't quite make sense because even if push_back is calling the copy constructor or something and copying the added item rather than pointing to it, the iterator is still passing over the same copies, no?
Interestingly enough, in my actual code, the class represented here by Item has a member variable that is a vector of shared pointers to objects of another class, and modifications to the objects being pointed to by those shared pointers persist between loops. This is why I suspect there's something funky with the unique_ptr.
Can anyone explain this behavior and explain how I may fix this issue while still using pointers?
When you write a range-based for loop like that:
std::vector<int> v = ...;
for(auto elt : v) {
...
}
the elements of v are copied into elt.
In your example, in each iteration, you modify the local copy of the Item and not the Item in the vector.
To fix your issue, use a reference:
for (auto& item : _my_vec)
{
item.setValue(10);
std::cout << item.getValue() << std::endl;
}
Vector of non-const objects seems to be treated as constant
If it was treated as constant, then the compiler would scream at you, because writing to a constant is treated as ill-formed and the compiler would be required to scream at you. The shown code compiles just fine, with no warnings.
I suspect that you may be referring to the fact that you don't modify the elements within the vector. That is because you modify auto item. That item is not an element of the vector, it is a copy of the item in the vector. You could refer to the item within that vector by using a reference: auto& item. Then modifications to item would be modifications to the referred element of the vector.

Safety of map operator[] when you dont want a default constructor

I recently ran into an interesting bug with a program at work. I would like to know a little bit more about how operator[] works with maps. Consider the following example code:
#include <map>
#include <iostream>
#include <utility>
#include <tuple>
class test
{
public:
test(int a, char b) {
a_ = a;
b_ = b;
}
void print() {
std::cout << a_ << " " << b_ << std::endl;
}
private:
int a_;
char b_;
};
int main()
{
std::map<int, test> mapper;
mapper.emplace(std::piecewise_construct,
std::forward_as_tuple<int>(1),
std::forward_as_tuple<int, char, double>(1, 'c', 2.34));
mapper[1].print();
}
The code is very simple, and the objective is pretty clear, I dont want to have a default constructor for the class test. This code wont compile however, because mapper[1].print() calls the default constructor.
The obvious solution here is to replace mapper[1].print() with mapper.find(1)->second.print(). I am just interested in why it is necessary for mapper[1] to create a test. Does this mean that every time in any code i have written with a map using operator[] that it creates a default and copies the class before calling its functions?
This seems like a huge waste of time, i understand its necessity during something like this: mapper[2] = test(1, 'a'). Is there not any way that it could tell that its not part of an operator= call? I guess not.
from Visual Studio 2012 library
mapped_type& operator[](key_type&& _Keyval)
{ // find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end()
|| this->_Getcomp()(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where,
pair<key_type, mapped_type>(
_STD move(_Keyval),
mapped_type())); // <---- call to default constructor
return (_Where->second);
}
as you can see it require mapped_type to be default construable to compile doesn't means it need to construct the object every time you call operator[]

Linux vs Windows std::map assignment constructors (Why such a difference?)

I was witnessing some unexpected behavior in a C++ application I am writing in Linux Ubuntu. I would construct an object with parameters and then put a copy of that object into a std::map using the assignment operator. I wrote a simple program to demonstrate this situation...
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Foo
{
public:
Foo(void) : _x(0)
{
cout << "Default" << endl;
}
Foo(int a) : _x(a)
{
cout << "Param" << endl;
}
Foo(Foo const &foo) :
_x(foo._x)
{
cout << "Copy" << endl;
}
Foo& operator=(Foo const &foo)
{
cout << "Assignment" << endl;
if (this != &foo)
{
_x = foo._x;
}
return *this;
}
int get(void)
{
return _x;
}
private:
int _x;
};
int main(int argc, char *argv [])
{
std::map<int, Foo> foos;
Foo a_foo(10);
foos[100] = a_foo;
return 0;
}
Here I am just printing out which constructor/operator gets called in what order so I can see how the construction and assignment works in the "main" function.
When I run this in Windows I get my expected output...
Param
Default
Assignment
When I run this in Linux I get the following output...
Param
Default
Copy
Copy
Assignment
Why are the two extra copy constructors there? It seems very inefficient to create the object so many times?
Thanks!
The answer lies in stl_map.h. Its behaviour depends on whether you compile with C++11 support or not. If you do then the STL can take advantage of move semantics to avoid unnecessary copying. VC++ uses the new language features by default but if you use g++ or clang you need to get used to using the -std=c++0x flag in 4.2 or -std=c++11 in newer versions.
With -std=c++11 set the output with g++4.8 is:
Param
Default
Assignment
Edit: Thank you very much for clarifying for me that my assumption that this was down to move semantics was incorrect. I'm leaving this answer in place to direct users to this better one.

In an STL Map of structs, why does the "[ ]" operator cause the struct's dtor to be invoked 2 extra times?

I've created a simple test case exhibiting a strange behavior I've noticed in a larger code base I'm working on. This test case is below. I'm relying on the STL Map's "[ ]" operator to create a pointer to a struct in a map of such structs. In the test case below, the line...
TestStruct *thisTestStruct = &testStructMap["test"];
...gets me the pointer (and creates a new entry in the map). The weird thing I've noticed is that this line not only causes a new entry in the map to be created (because of the "[ ]" operator), but for some reason it causes the struct's destructor to be called two extra times. I'm obviously missing something - any help is much appreciated!
Thanks!
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
the code above outputs the following...
/*
Marker One
TestStruct Constructor! //makes sense
TestStruct Destructor! //<---why?
TestStruct Destructor! //<---god why?
Marker Two
TestStruct Destructor! //makes sense
*/
...but I don't understand what causes the first two invocations of TestStruct's destructor?
(I think the last destructor invocation makes sense because testStructMap is going out of scope.)
The functionality of std::map<>::operator[] is equivalent to
(*((std::map<>::insert(std::make_pair(x, T()))).first)).second
expression, as specified in the language specification. This, as you can see, involves default-constructing a temporary object of type T, copying it into a std::pair object, which is later copied (again) into the new element of the map (assuming it wasn't there already). Obviously, this will produce a few intermediate T objects. Destruction of these intermediate objects is what you observe in your experiment. You miss their construction, since you don't generate any feedback from copy-constructor of your class.
The exact number of intermediate objects might depend on compiler optimization capabilities, so the results may vary.
You have some unseen copies being made:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct TestStruct;
int main (int argc, char * const argv[]) {
map<string, TestStruct> testStructMap;
std::cout << "Marker One\n";
//why does this line cause "~TestStruct()" to be invoked twice?
TestStruct *thisTestStruct = &testStructMap["test"];
std::cout << "Marker Two\n";
return 0;
}
struct TestStruct{
TestStruct(){
std::cout << "TestStruct Constructor!\n";
}
TestStruct( TestStruct const& other) {
std::cout << "TestStruct copy Constructor!\n";
}
TestStruct& operator=( TestStruct const& rhs) {
std::cout << "TestStruct copy assignment!\n";
}
~TestStruct(){
std::cout << "TestStruct Destructor!\n";
}
};
Results in:
Marker One
TestStruct Constructor!
TestStruct copy Constructor!
TestStruct copy Constructor!
TestStruct Destructor!
TestStruct Destructor!
Marker Two
TestStruct Destructor!
add the following to TestStruct's interface:
TestStruct(const TestStruct& other) {
std::cout << "TestStruct Copy Constructor!\n";
}
Your two mysterious destructor calls are probably paired with copy constructor calls going on somewhere within the std::map. For example, it's conceivable that operator[] default-constructs a temporary TestStruct object, and then copy-constructs it into the proper location in the map. The reason that there are two destructor calls (and thus probably two copy constructor calls) is implementation-specific, and will depend on your compiler and standard library implementation.
operator[] inserts to the map if there is not already an element there.
What you are missing is output for the compiler-supplied copy constructor in your TestStruct, which is used during container housekeeping. Add that output, and it should all make more sense.
EDIT: Andrey's answer prompted me to take a look at the source in Microsoft VC++ 10's <map>, which is something you could also do to follow this through in all its gory detail. You can see the insert() call to which he refers.
mapped_type& operator[](const key_type& _Keyval)
{ // find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end()
|| this->comp(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where,
value_type(_Keyval, mapped_type()));
return ((*_Where).second);
}
so the lesson is - dont put structs in a map if you care about their lifecycles. Use pointers, or even better shared_ptrs to them
You can check it out through this more simple code.
#include <iostream>
#include <map>
using namespace std;
class AA
{
public:
AA() { cout << "default const" << endl; }
AA(int a):x(a) { cout << "user const" << endl; }
AA(const AA& a) { cout << "default copy const" << endl; }
~AA() { cout << "dest" << endl; }
private:
int x;
};
int main ()
{
AA o1(1);
std::map<char,AA> mymap;
mymap['x']=o1; // (1)
return 0;
}
The below result shows that (1) line code above makes (1 default const) and (2 default copy const) calls.
user const
default const // here
default copy const // here
default copy const // here
dest
dest
dest
dest