3
#include <vector>
#include <iostream>

typedef struct {
   unsigned short a;
   unsigned short b;
   unsigned long  c;
}T;

int main(int,char**)
{
    std::vector<T> v;
    v.resize(256);
    std::cout << "a=" << v[0].a << " b=" << v[0].b << " c=" << v[0].c << "\n";
    return 0;
}

What will be v[0].a (and b and c)?

I am starting looking at the draft N4659 Working Draft, Standard for Programming Language C++ searching for vector::resize:

26.3.11.3 vector capacity [vector.capacity] (at clause 13)

void resize(size_type sz);

Effects: If sz < size(), erases the last size() - sz elements from the sequence. Otherwise, appends sz - size() default-inserted elements to the sequence.

from there I need to know what default-inserted means and I arrive at:

26.2.1 General container requirements [container.requirements.general] (at clause 15.2)

— An element of X is default-inserted if it is initialized by evaluation of the expression

allocator_traits<A>::construct(m, p)

where p is the address of the uninitialized storage for the element allocated within X.

Now, I need to know what happen inside construct, I found this note

26.2.1 General container requirements [container.requirements.general] (at the end of clause 15)

[ Note: A container calls allocator_traits<A>::construct(m, p, args) to construct an element at p using args, with m == get_allocator(). The default construct in allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition. — end note ]

Am I fine? Does my snippet use a specialized allocators? I think that at the end my snippet will call new T() and now, according to https://stackoverflow.com/a/8280207 I think a, b and c, will be 0, am I correct?

Alessandro Jacopson
  • 18,047
  • 15
  • 98
  • 153

4 Answers4

6

Yes, you're correct. You didn't use a specialized (customized) allocator. At last the elememts get value initialized. From DefaultInsertable:

By default, this will call placement-new, as by ::new((void*)p) T() (that is, value-initialize the object pointed to by p).

And as the result of value initialization, all the members of T will be zero-initialized.

(emphasis mine)

if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
4

The default behavior of

allocator_traits<A>::construct(m, p)

is defined in [allocator.traits.members]/5 it it states it does

Effects: Calls a.construct(p, std::forward<Args>(args)...) if that call is well-formed; otherwise, invokes ::new (static_­cast<void*>(p)) T(std::forward<Args>(args)...).

Since std::vector<T> v; use the default allocator std::allocator, and std::allocator lacks a construct member, you fall back to the placement new initialization and if you expand it out you'll have

::new (static_­cast<void*>(p)) T();

and if we look up what T() does we get from [dcl.init]/11 that

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

and [dcl.init]/8 states that value initialization will

if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;

So all of the members of each newly created object will be zero initialized which means in this case they will all have the value of 0 since they are built in types.

Alessandro Jacopson
  • 18,047
  • 15
  • 98
  • 153
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
3

Am I fine? Does my snippet use a specialized allocators?

Yes you are, no the allocator is not specialized. The default allocator used by std::vector<T> is std::allocator<T>. Currently std::allocator<T> is still specified to have a construct member which does the same thing. But that is a deprecated member. Regardless, even if it's removed in the future entirely, the call via std::allocator_traits is still going to behave the same.

[allocator.traits.members]

template <class T, class... Args>
  static void construct(Alloc& a, T* p, Args&&... args);

Effects: Calls a.construct(p, std​::​forward<Args>(args)...) if that call is well-formed; otherwise, invokes ​::​new(static_­cast<void*>(p)) T(std​::​forward<Args>(args)...).

As for what new T() does, you are 100% correct.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

Am I fine?

Yes.

Does my snippet use a specialized allocators?

No. You use the default allocator which is std::allocator.

I think that at the end my snippet will call new T() and now, according to https://stackoverflow.com/a/8280207 I think a, b and c, will be 0, am I correct?

Correct.

eerorika
  • 232,697
  • 12
  • 197
  • 326