4

I am interested if creating a new std::vector (or calling its assign method) creates a copy of the data?

For example,

void fun(char *input) {
    std::vector<char> v(input, input+strlen(input));
    // is it safe to assume that the data input points to was COPIED into v?
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
bodacydo
  • 75,521
  • 93
  • 229
  • 319

5 Answers5

11

Yes. Elements are always copied into or out of STL containers. (At least until move semantics are added in C++0x)

EDIT: Here's how you can test for copying yourself:

#include <vector>
#include <iostream>

class CopyChecker
{
public:
    CopyChecker()
    {
        std::cout << "Hey, look! A new copy checker!" << std::endl;
    }
    CopyChecker(const CopyChecker& other)
    {
        std::cout << "I'm the copy checker! No, I am! Wait, the"
            " two of us are the same!" << std::endl;
    }
    ~CopyChecker()
    {
        std::cout << "Erroap=02-0304-231~No Carrier" << std::endl;
    }
};

int main()
{
    std::vector<CopyChecker> doICopy;
    doICopy.push_back(CopyChecker());
}

The output should be:

Hey, look! A new copy checker!
I'm the copy checker! No, I am! Wait, the two of us are the same!
Erroap=02-0304-231~No Carrier
Erroap=02-0304-231~No Carrier

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • So what will happen in C++0x? Will the code like this break? Or there will be a special construct for "move semantics"? – bodacydo Jul 09 '10 at 03:45
  • @bodacydo: In C++0x IIRC the elements are allowed to be move constructed into the vector instead of copying. This is a performance optimization. For example, if you have a string, your object can copy just the pointer to the string into the container instead of copying the entire string itself. Your type would need to have a move constructor to enable the new behavior in C++0x. – Billy ONeal Jul 09 '10 at 03:47
  • 1
    @Billy ONeal: You also need to use `std::move` to use move semantics. Rvalue reference arguments only bind to temporaries. – rlbond Jul 09 '10 at 03:54
  • Billy, thanks for explaining. Much appreciated. Also your example is funny. :) – bodacydo Jul 09 '10 at 03:54
  • @rlbond: I see no way to construct the vector via moving from the source. What syntax do you propose? `std::vector v(std::move(input), input+strlen(input));` or something like that won't work, the standard says the copy constructor will be called for the range constructor. See my own answer for a possible solution ;) – fredoverflow Jul 09 '10 at 08:59
9

Elements are always copied into or out of STL containers.

Although the element may just be a pointer, in which case the pointer is copied but not the underlying data

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • In addition, when the element type is a pointer, the vector destruction will not do anything with the data that each pointer points to - it just sets the pointer to zero or some garbage. This means that object pointers stored in vector need to be taken care of. Plus, there is an additional risk of double-deletion if the ownership of the pointers are not clearly defined. The benefit is, of course, speed. – rwong Jul 09 '10 at 04:20
  • 2
    @rwong: When a vector of pointers is destructed, why would the vector set their values to anything? They're about to cease existing. – GManNickG Jul 09 '10 at 06:11
  • I was wrong, then. I just want to say that there is no automatic cleanup if the element type is a pointer. – rwong Jul 09 '10 at 22:53
1

About the move semantics, here is how you could move the contents in C++0x if you wanted to:

void fun_move(char *input)
{
    std::vector<char> v;
    auto len = strlen(input);
    v.reserve(len);
    std::move(input, input+len, std::back_inserter(v));
}
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
0

If you want your data to be moved, use std::swap_ranges, but you have to allocate for memory first :

vector<T> v;
v.reserve(std::distance(beg, end));
std::swap_ranges(beg, end, v.begin());
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • The first line default-constructs a T and then copy constructs that n times -- this doesn't seem very performant to me... – fredoverflow Jul 09 '10 at 10:56
  • Now you have undefined behavior. You need to use `back_inserter` here like that shown in FredOverflow's answer. – Billy ONeal Jul 09 '10 at 12:58
0

If you do not want the object copy semantics, then you can create a vector of pointers-to-objects instead so that only the pointer is copied. However you then have to ensure that the pointers then remain valid for the lifetime of the container.

Clifford
  • 88,407
  • 13
  • 85
  • 165