简体   繁体   中英

std::vector::assign - reallocates the data?

I am working with STL library and my goal is to minimize the data reallocation cases. I was wndering, does

std::vector::assign(size_type n, const value_type& val)

reallocated the data if the size is not changed or does is actually just assign the new values (for example, using operator=) ?

The STL documentation at http://www.cplusplus.com/ sais the following (C++98):

In the fill version (2), the new contents are n elements, each initialized to a copy of val. If a reallocation happens,the storage needed is allocated using the internal allocator.

Any elements held in the container before the call are destroyed and replaced by newly constructed elements (no assignments of elements take place). This causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.

The phrase "no assignments of elements take place" make it all a little confusing.

So for example, I want to have a vector of classes (for example, cv::Vec3i of OpenCV). Does this mean, that

  1. the destructor or constructor of cv::Vec3i will be called?
  2. a direct copy of Vec3i memory will be made and fills the vector?
  3. what happens, if my class allocates memory at run time with new operator? This memory cannot be accounted for by plain memory copying. Does it mean, that assign() should not be used for such objects?

EDIT: the whole purpose of using assign in this case is to set all values in the vector to 0 (in case I have std::vector< cv::Vec3i > v). It will be done many-many times. The size of std::vector itself will not be changed.

what i want to do (in a shorter way) is the following:

 for(int i=0; i<v.size(); i++)  
   for(int j=0; j<3; j++)
     v[i][j] = 0;

right now I am interested in C++98

std::vector.assign(...) does not reallocate the vector if it does not have to grow it. Still, it must copy the actual element.

If you want to know what the standard guarantees, look in the standard: C++11 standard plus minor editorial changes.

I assume that you have a vector filled with some data and you call an assign on it, this will:

  1. destroy all the elements of the vector (their destructor is called) like a call to clear()
  2. fill the now-empty vector with n copies of the given object, which must have a copy constructor.

So if your class allocates some memory you have to:

  1. take care of this in your copy constructor
  2. free it in the destructor

Reallocations happen when the size exceed the allocated memory (vector capacity). You can prevent this with a call to reserve(). However I think that assign() is smart enough to allocate all the memory it needs (if this is more than the already allocated) before starting to fill the vector and after having cleared it.

You may want to avoid reallocations because of their cost, but if you are trying to avoid them because your objects cannot handle properly, then I strongly discourage you to put them in a vector.

The semantics of assign are defined the standard in a quite straightforward way:

void assign(size_type n, const T& t);

Effects:

erase(begin(), end());
insert(begin(), n, t);

This means that first the destructors of the elements will be called. The copies of t are made in what is now a raw storage left after the lifetime of the elements ended.

The requirements are that value_type is MoveAssignable (for when erase doesn't erase to the end of the container and needs to move elements towards the beginning).

insert overload used here requires that value_type is CopyInsertable and CopyAssignable.

In any case, vector is oblivious to how your class is managing its own resources. That's on you to take care of. See The Rule of Three.

As in the case of vector::resize method,

std::vector::assign(size_type n, const value_type& val)

will initialize each element to a copy of "val" . I prefer to use resize as it minimizes the number of object instanciations/destructions, but it does the same. Use resize if you want to minimize the data realloc, but keep in mind the following:

While doing this is safe for certain data structures, be aware that assigning /pushing elements of a class containing pointers to dynamically allocated data (eg with a new in the constructor) may cause havoc.

If your class dynamically allocates data then you should reimplement the YourClass::operator= to copy the data to the new object instead of copying the pointer.

Hope that it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM