Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 vector makes copies on rvalue [duplicate]

I have some strange behavior on std::vector with adding rvalues:

#include <iostream>
#include <vector>

class A {
public:
    A():i_{5}{std::cout << "default" << std::endl;}
    A(const A &data) { std::cout << "copied!" << std::endl; }
    A(A &&data) {      std::cout << "moved " << std::endl; }
    int i_;
};

int main(int argc, char *argv[]) {
    std::vector<A> datavec;
    datavec.push_back(A{});
    datavec.push_back(A{});
    return 0;
}

output is:

default
moved 
default
moved 
copied!

So vector still creates copies of A, the more pushes I do - the more copies I get. However, if I replace move constructor with default one A(A &&data) = default; or delete copy constructor with A(const A &data) = delete; I get right result where no copies are made. I also have no copies if I first call datavec.reserve with enough size. I use gcc version 5.4.0 with no specific arguments

g++ -std=c++11 -o main ../main.cpp

Have you got any thoughts on why vector makes copies of obvious rvalues? I hope it is not some bug of STL

like image 864
Sorcerer Avatar asked Apr 05 '17 15:04

Sorcerer


1 Answers

The std::vector is copying your elements during internal buffer reallocation. It is choosing to copy instead of moving because your move constructor is not marked noexcept. Marking it...

A(A &&) noexcept {      std::cout << "moved " << std::endl; }

...will fix the issue.

Telling the compiler that your move constructor will not throw allows std::vector's implementation to move during internal reallocation, fulfilling the exception guarantees demanded by the C++ Standard.

Alternatively, you can std::vector::reserve your container in advance to prevent the growth of the internal buffer.

like image 93
Vittorio Romeo Avatar answered Oct 21 '22 03:10

Vittorio Romeo