Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 rvalue reference calling copy constructor too

Tags:

I've been testing some C++11 features from some some. I came across r-value references and move constructors.

I implemented my first move constructor, here it is:

#include <iostream> #include <vector> using namespace std;  class TestClass{  public:     TestClass(int s):         size(s), arr(new int[s]){     }     ~TestClass(){         if (arr)             delete arr;     }     // copy constructor     TestClass(const TestClass& other):             size(other.size), arr(new int[other.size]){         std::copy(other.arr, other.arr + other.size, arr);     }      // move constructor     TestClass(TestClass&& other){         arr=other.arr;         size=other.size;          other.arr=nullptr;         other.size=0;     }  private:     int size;     int * arr; };  int main(){     vector<TestClass> vec;      clock_t start=clock();     for(int i=0;i<500000;i++){         vec.push_back(TestClass(1000));     }     clock_t stop=clock();     cout<<stop-start<<endl;      return 0; } 

The code works fine. Anyway putting a std::cout inside the copy constructor i noticed that it gets called! And a lot of times.. (move constructor 500000 times, copy constructor 524287 times).

What surprised me more is that if i comment out the copy constructor from the code, the whole program gets a lot faster, and this time the move constructor is called 1024287 times.

Any clue?

like image 263
Luke Givens Avatar asked Aug 06 '13 16:08

Luke Givens


People also ask

What is R value Referene in C ++ 11?

In C++11, however, the rvalue reference lets us bind a mutable reference to an rvalue, but not an lvalue. In other words, rvalue references are perfect for detecting whether a value is a temporary object or not.

Does passing by reference call copy constructor?

When an object (or built-in type) is passed by reference to a function, the underlying object is not copied. The function is given the memory address of the object itself. This saves both memory and CPU cycles as no new memory is allocated and no (expensive) copy constructors are being called.

Why call by reference is used in copy constructor?

It is necessary to pass object as reference and not by value because if you pass it by value its copy is constructed using the copy constructor. This means the copy constructor would call itself to make copy. This process will go on until the compiler runs out of memory.

What is the use of rvalue reference?

Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.


1 Answers

Put noexcept on your move constructor:

TestClass(TestClass&& other) noexcept { 

Elaboration: I was going to give this one Pierre, but unfortunately the cppreference source is only approximately correct.

In C++03

vector<T>::push_back(T) 

has the "strong exception guarantee". That means that if the push_back throws an exception, the vector is left in the same state it had prior to the call to push_back.

This guarantee is problematic if the move constructor throws an exception.

When the vector reallocates, it would like to move the elements from the old buffer to the new. However if any one of those moves throws an exception (besides the first), then it is left in a state where the old buffer has been modified, and the new buffer doesn't yet contain everything it is supposed to. The vector can't restore the old buffer to its original state because it would have to move elements back to do so, those moves might also fail.

So a rule was laid down for C++11:

  1. If T has a noexcept move constructor, that can be used to move the elements from the old buffer to the new.

  2. Otherwise if T has a copy constructor, that will be used instead.

  3. Otherwise (if there is no accessible copy constructor), then the move constructor will be used after all, however in this case, the strong exception safety guarantee is no longer given.

Clarification: "copy constructor" in rule 2 means a constructor taking a const T&, not one of those weenie so-called T& copy constructors. :-)

like image 140
Howard Hinnant Avatar answered Oct 05 '22 23:10

Howard Hinnant