views:

146

answers:

5

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?
}

Thanks, Boda Cydo.

+11  A: 

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
Thank you Billy.
bodacydo
So what will happen in C++0x? Will the code like this break? Or there will be a special construct for "move semantics"?
bodacydo
@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
@Billy ONeal: You also need to use `std::move` to use move semantics. Rvalue reference arguments only bind to temporaries.
rlbond
Billy, thanks for explaining. Much appreciated. Also your example is funny. :)
bodacydo
@bodacydo: No problem :) Thanks!
Billy ONeal
@rlbond: I see no way to construct the vector via moving from the source. What syntax do you propose? `std::vector<char> 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
+1 for No carrier
Tarantula
+9  A: 

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
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
@rwong: When a vector of pointers is destructed, why would the vector set their values to anything? They're about to cease existing.
GMan
I was wrong, then. I just want to say that there is no automatic cleanup if the element type is a pointer.
rwong
+1  A: 

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
Is it C++1x yet? The optimism of 0x seems unfounded at this date. ;)
Greg D
@Greg D: x is an hexadecimal digit...
Alexandre C.
A: 

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.
The first line default-constructs a T and then copy constructs that n times -- this doesn't seem very performant to me...
FredOverflow
you're right, I edit the code.
Alexandre C.
@Alex: Now you have undefined behavior. You need to use `back_inserter` here like that shown in FredOverflow's answer.
Billy ONeal
A: 

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