0

I can't figure out how push_back(const value_type& val) exactly works, in docs it says about val that

val is Value to be copied (or moved) to the new element ...

  1. How it can be copied when it takes val by reference ?

  2. Will that copying ever call the copy constructor of val ?

and what's exactly happening here ?

#include <iostream>
#include <vector>    
using namespace std;    
struct x
{
    x(int v = 0) : v(v) {}
    int v;
};    
vector<vector<x>> parts;    
void fillParts()
{
    vector<x> values = { x(1), x(2), x(3) };
    parts.push_back(values);
}        
int main()
{
    fillParts();  
    parts[0][0].v = -123;
    cout << parts[0][0].v;    // -123
    return 0;
}

this runs with no erros, is parts[0] is a reference to local vector values or a copy ? if it is a reference shouldn't it at least give some warnings saying that your accessing and modifying local objects of freed stack ?

Community
  • 1
  • 1
ampawd
  • 968
  • 8
  • 26
  • Values are copied using the copy constructor, the `parts` vector copies the `values` vector when doing the `push_back`, so when accessing them they are not freed. The local variable `values` was indeed freed but a copied vector with the same underlaying data is stored in 'parts`. – Javier Mr Aug 22 '16 at 10:44
  • @JavierMr yeah but `push_back` takes by reference - then how it perform copying of `values` vector ? – ampawd Aug 22 '16 at 10:49
  • 1
    @ampawd Why not? `Copy Constructor` takes by reference in general and it performs copying perfectly. – Dean Seo Aug 22 '16 at 10:51
  • I think compiler may optimize the code to use `void push_back (value_type&& val);` and you will have move assignment operator in action. Anyway, it will be either copy or moved entity. Actually, you can debug it with F11. – Yola Aug 22 '16 at 10:54
  • @Yola hmm that sounds interesting, but moving is a c++11 feature, in previous standard it won't do that – ampawd Aug 22 '16 at 10:56
  • So you will have a copy. And forget about my words about debugging, because in debug builds compiler probably will not use such optimization. – Yola Aug 22 '16 at 10:58
  • @Yola there is no "optimization" for push_back with an lvalue to actually match rvalue parameter. The author would have to write `std::move`. There are better approaches. – M.M Aug 22 '16 at 11:06
  • @M.M thanks for pointing this out, after some testing i also think so, at least because silent moving would be undesirable in case the user wants destructor to be called. – Yola Aug 22 '16 at 11:16

2 Answers2

3

How it can be copied when it takes val by reference?

Think of a copy constructor. It takes parameter by reference, and it performs copying perfectly.

class Bar
{
public:
    Bar(const Bar & rhs); // by reference, to copy.
};

Will that copying ever call the copy constructor of val ?

Copy operation uses copy constructor.

You can actually see if it's copied, or moved by providing user-defined constructors.

struct x
{
public:
    x(const x & rhs)
    {
        // Some copy operation.
        std::cout << "Copied" << std::endl;
    }

    x(x && rhs)
    {
        // Some move operation.
        std::cout << "Moved" << std::endl;
    }
};
Dean Seo
  • 5,486
  • 3
  • 30
  • 49
  • 1
    note: for `struct x` as in the question, you'll want to actually perform the copy of the member variable in those constructors! – M.M Aug 22 '16 at 11:05
  • is `vector` copy constructor looks something like this `vector(const vector& rhs)` ? – ampawd Aug 22 '16 at 11:06
  • @ampawd You're being confused between constructor of `x` and `std::vector`. Now, you're looking at the other(or wrong) side of this copying operation. You're calling `push_back`, (not constructor) – Dean Seo Aug 22 '16 at 11:09
  • @DeanSeo No I actually got what youre saying, ... just to clarify things – ampawd Aug 22 '16 at 11:11
  • @DeanSeo and in my example copy ctor of vector also will be called because `parts[0]` is a vector – ampawd Aug 22 '16 at 11:13
  • @ampawd You're right. Your `std::vector` takes another `std::vector`, so yes it invokes its copy constructor since `push_back` is copy-based. (And it makes sense! You don't want `push_back` to *move* a given argument, because you'll maybe still want to use that object.) – Dean Seo Aug 22 '16 at 11:20
0

You can try this

class A
{
public:
    A() {}
    A(const A&) { cout << "copy cons" << endl; }
    A& operator= (A &&) { cout << "move" << endl; };
    A& operator= (const A &) { cout << "copy" << endl; };
};
vector<A> parts;
void fillParts()
{
    A a;
    parts.push_back(a);
}
int main()
{
    fillParts();
    return 0;
}

I got copy cons called in both debug and release builds.

Yola
  • 18,496
  • 11
  • 65
  • 106