5

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

coffee
  • 703
  • 2
  • 9
  • 14
  • To minimise reallocation, use `std::shared_ptr`. You can freely copy these pointers from one to another container, just the pointer itself is copied. Using a "read only" object approach it should solve this problem. – Flovdis Apr 14 '14 at 15:11
  • What it probably means with "no assignment of elements..." is that the new elements are copy-constructed from the parameter, and that no copy assignment occurs. Therefore if you have a well-defined copy ctor for the type stored, then you should have no worries. – bstamour Apr 14 '14 at 15:16
  • @Flovdis isn't shared ptr part of C++11 ? Thought we are talking about C++98 here.. – Яois Apr 14 '14 at 15:16
  • @KeillRandor Actually there is no clear statement which C++ revision is used, do you assume this because the question cites from the C++98 documentation? Actually I just wanted to hint, that there is an alternative to minimise large allocations programatically using a "shared data" concept. – Flovdis Apr 14 '14 at 15:22
  • @Flovdis you are right, if C++11 support is available i'd prefer to use smart pointers as well. – Яois Apr 14 '14 at 15:30
  • C++98 is sufficient for `boost::shared_ptr`, and pre-C++11 `std::tr1::shared_ptr` is also an option for this purpose. – MSalters Apr 14 '14 at 15:51
  • I don't have big amounts of data.. rather, i have a lot of small data objects, and I don't want to deallocate and allocate them each time. plus, I wanted to use assign to basically reset the values of the class. in case of class being cv::Vec3i , i want all values being set to 0 through this operation – coffee Apr 14 '14 at 17:03

4 Answers4

1

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.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
1

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.

DarioP
  • 5,377
  • 1
  • 33
  • 52
1

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.

Community
  • 1
  • 1
jrok
  • 54,456
  • 9
  • 109
  • 141
  • could you please explain where the standard defines `assign` to be `erase`+`insert `? thank you. https://stackoverflow.com/q/51892382/8414561 – Dev Null Aug 17 '18 at 13:45
0

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 (e.g. 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!

Яois
  • 3,838
  • 4
  • 28
  • 50