7

If I assign or copy one vector to another (that has the same or bigger capacity than the size of the former), can I assume that the buffer of the latter will be reused?

The following example demonstrates that I can, however, is it guaranteed by the standard? Is there any difference between behaviour of std::vector::assign and std::vector::operator= in this regard?

#include <vector>
#include <iostream>
#include <cassert>

int main()
{
    std::vector a {1, 2, 3, 4, 5};
    std::vector b {1, 2, 3, 4};
    std::vector c {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::cout << "1 ==== " << a.capacity() << " " << a.data() << std::endl;

    const auto* pa = a.data();   
    a = b;
    assert(pa == a.data());
    std::cout << "2 ==== " << a.capacity() << " " << a.data() << std::endl;

    a = c;
    assert(pa != a.data());
    std::cout << "3 ==== " << a.capacity() << " " << a.data() << std::endl;
}

Live example.

Update: This answer mentions that

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

is equivalent to

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

Does the standard really formulate it this way and does it apply to all overloads of std::vector::assign?

Dev Null
  • 4,731
  • 1
  • 30
  • 46
  • 2
    Usually yes, but it actually depends on the allocator compatibilities and allocator propagation: if the allocator is not propagated on assignment or if the source allocator can release memory of the target allocator then the target buffer is reused (target => right side of assignment operator, source=> left side of assignment operator). – Oliv Aug 17 '18 at 09:41
  • 1
    Sorry, I can't find anything related with "this answer mentioned" in the newest draft. The standard (as far as I found) only says "Replaces elements in a with n copies of t. Invalidates..." See [http://eel.is/c++draft/sequence.reqmts#tab:containers.sequence.requirements] – L. F. Aug 17 '18 at 10:16
  • Maybe the requirements on `vector::reserve()` can be used to prove this. Something along the lines of: insert a `a.reserve(a.size());` before the assignment, and the assignment might be constrained by the reserve() to use the same storage (e.g. the iterator to a[0] is guaranteed to stay valid). As a `v.reserve(v.size());` is clearly a no-op and always holds for a vector, . But I don't have the time to track the standard references at this moment. – Sjoerd Aug 17 '18 at 12:09
  • Also note that if the allocator does not propagate on copy construct, the original buffer *has* (guaranteed) *to be released* anyway. – L. F. Aug 19 '18 at 03:27
  • @L.F. then `assign` is better than `operator=`, isn't it? – Dev Null Aug 27 '18 at 00:22
  • Why do you say this? I don't think so. – L. F. Aug 27 '18 at 01:19
  • @L.F. because, unlike `operator=`, it doesn't care about the allocator. – Dev Null Aug 27 '18 at 01:58
  • Depending on your mind, it can be or not. There exist overloads of `operator=` that don't care about the allocator. The aims of `operator=` and `assign` are different: `operator=` is used to completely rebuild the current `vector` based on another `vector`; `assign` is used to assign new values to the current `vector`. That's why `assign` do not care about the allocator. If you want to change the allocator, you have to rebuild the `vector` completely, or you will be in an embarrassing situation that the elements are allocated by different allocators. Then the `vector` won't destruct properly. – L. F. Aug 27 '18 at 02:30

1 Answers1

4

Short answer

No.

Not so short answer

The standard does not manually define these operations on vector. It only defines them as a requirement for containers. [vector] says

A vector satisfies all of the requirements of a container and of a reversible container (given in two tables in [container.requirements]), of a sequence container, including most of the optional sequence container requirements ([sequence.reqmts]), of an allocator-aware container (Table 67), and, for an element type other than bool, of a contiguous container. The exceptions are the push_­front, pop_­front, and emplace_­front member functions, which are not provided. Descriptions are provided here only for operations on vector that are not described in one of these tables or for operations where there is additional semantic information.

The only places where these operation are mentioned are Container requirements and Sequence container requirements. Nothing supports your assumption.

L. F.
  • 19,445
  • 8
  • 48
  • 82
  • At least this is a question of implementation quality. And on all implementation, the best is done to reduce the number of memory allocation because it is expensive. – Oliv Aug 17 '18 at 09:49
  • If I understood correctly, OP is looking for standard guarantee :P That's not exactly the same thing as implementations – L. F. Aug 17 '18 at 09:50
  • Depends where you are working. The standard is the theory, the implementation is the reality. If you are making a student work you can use the standard. But if you are writting the code of a cardiac pacemaker your analyse will be based on the implementation of the library, a heart is a real thing! – Oliv Aug 17 '18 at 09:55
  • In this particular context we are language lawyers ;P see the tags – L. F. Aug 17 '18 at 09:57
  • Indeed, I did not saw this one! – Oliv Aug 17 '18 at 09:58
  • That's normal since it is newly added – L. F. Aug 17 '18 at 09:59
  • @Oliv, @ L.F. please see updated part in the question. – Dev Null Aug 17 '18 at 10:13
  • @Oliv - Using an analogy of a pacemaker (or any safety related application) is inappropriate here. Anyone doing such development would be very unlikely to employ any standard container that dynamically allocates memory. Dynamic memory allocation introduces various properties (e.g. unpredictability of timing of operations) that make it very difficult and costly to verify program correctness to a level of rigour required in a safety-related application. – Peter Aug 17 '18 at 10:27
  • @Peter The aim of an example is not to speek about the example in itself but to illustrate an abstraction. But since you are there, I agree, the default allocator are unpredictable, but that is just the default behavior. One can make predictable allocator. There are also predictable malloc implementations. The real problem in safety related application are often caused by a cognitive bias. We believe that a code tested a billion time by millions of coder is less secure than a piece of code we have written and tested using a systematic procedure. Are we right to be sure of this test procedure? – Oliv Aug 17 '18 at 10:41
  • 1
    @Oliv - Yes, I realise you were trying to illustrate an abstraction. You picked a terrible example though. But thanks for demonstrating that you don't actually understand what safety-related development entails. If testing is used to justify claims in a safety case, there is generally a requirement to separately justify a claim that the testing actually does provide appropriate levels of evidence that requirements under test are met. It is not just a case of trusting a systematic process over alternatives because of cognitive bias. – Peter Aug 17 '18 at 11:07
  • @Peter Yes indeed, I have only worked on application that make people fill unsafe actually. But I have quitted! – Oliv Aug 17 '18 at 11:13
  • really you could rely on that , until you do some exotic stuff so old buffer will be optimized out. Say it could be swapped with other's one if latter been deleted after i guess. – Алексей Неудачин Aug 18 '18 at 17:41