nocekdw
nocekdw

Reputation: 53

Memory allocation difference between vector::reserve and classical memory allocation

I know that both vector and dynamic memory allocation are using heap.

char *n = new char[5000000000];

I can observe increasing allocated memory about 700mb.

    vector<char> v;
    v.reserve(5000000000);

and in this case, it increased over 4GB.

Is there a difference between the two methods?

Upvotes: 1

Views: 116

Answers (1)

dfrib
dfrib

Reputation: 73196

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


From [vector.capacity]/3:

void reserve(size_type n);

Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). If an exception is thrown other than by the move constructor of a non-CopyInsertable type, there are no effects.

A given (compiler) implementation is free to implement its own (typically amortized) growth strategy, and the only guarantee we can use when analyzing a std::vector object growth is that the capacity() after invocation of reserve() will be greater or equal to the argument passed for the reserve() function. I.e., an implementation is not allowed to allocate less than the provided (asked for) argument, even if it can realize, by some clever program analysis, that parts of the allocated storage will never be used.

When allocating memory using a new-expression, however, there are a number of special rules, as governed by [expr.new]/10 through [expr.new]/12, that allow implementers a larger freedom in how allocation resulting from a new-expression is performed; e.g. from [expr.new]/10 [extract]:

An implementation is allowed to omit a call to a replaceable global allocation function ([new.delete.single], [new.delete.array]). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression. The implementation may extend the allocation of a new-expression e1 to provide storage for a new-expression e2 if [...]

Depending on the context of your particular program, this could explain why you see a smaller dynamic memory footprint for the result of the new char[5000000000] expression as compared to the v.reserve(5000000000) invocation.

Upvotes: 1

Related Questions