std :: vector of vector:在向量调整大小后,struct的成员的初始值是多少?

问题描述 投票:3回答:4
#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;
}

什么是v[0].a(和bc)?

我开始查看N4659 Working Draft, Standard for Programming Language C++寻找vector::resize的草案:

26.3.11.3载体容量[vector.capacity](第13条)

void resize(size_type sz);

效果:如果sz < size(),从序列中删除最后的size() - sz元素。否则,将sz - size()默认插入元素附加到序列中。

从那里我需要知道什么是默认插入的手段,我到达:

26.2.1一般容器要求[container.requirements.general](第15.2条)

- 如果通过评估表达式初始化X的元素,则默认插入该元素

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

其中pX中分配的元素的未初始化存储的地址。

现在,我需要知道construct内部发生了什么,我发现了这个说明

26.2.1一般容器要求[container.requirements.general](在第15条末尾)

[注意:一个容器调用allocator_traits<A>::construct(m, p, args)使用pargsm == get_allocator()构造一个元素。 allocator中的默认构造将调用::new((void*)p) T(args),但专用分配器可以选择不同的定义。 - 结束说明]

我很好吗?我的代码片段是否使用专门的分配器?我认为最后我的片段将调用new T(),现在,根据https://stackoverflow.com/a/8280207,我认为abc,将是0,我是否正确?

c++ struct language-lawyer standards default-constructor
4个回答
4
投票

的默认行为

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

它在[allocator.traits.members]/5中定义,它表明它确实如此

效果:如果调用格式良好,则调用a.construct(p, std::forward<Args>(args)...);否则,调用::new (static_­cast<void*>(p)) T(std::forward<Args>(args)...)

由于std::vector<T> v;使用默认分配器std::allocator,而std::allocator缺少construct成员,因此您将回退到新的初始化位置,如果将其展开,则会有

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

如果我们查看T()我们从[dcl.init]/11那里得到了什么

初始化器为空的括号集(即())的对象应进行值初始化。

[dcl.init]/8声明值初始化将

如果T是一个(可能是cv限定的)类类型而没有用户提供或删除的默认构造函数,那么该对象是零初始化的,并且检查默认初始化的语义约束,如果T有一个非平凡的默认构造函数,该对象是默认初始化的;

因此,每个新创建的对象的所有成员都将初始化为零,这意味着在这种情况下,它们都将具有0的值,因为它们是以类型构建的。


6
投票

是的,你是对的。您没有使用专门的(自定义的)分配器。最后,元素得到了value initialized。来自DefaultInsertable

默认情况下,这将调用placement-new,如::new((void*)p) T()(即,对p指向的对象进行值初始化)。

而作为value initialization的结果,T的所有成员将被零初始化。

(强调我的)

如果T是一个类型,其默认构造函数既不是用户提供也不是删除(也就是说,它可能是一个具有隐式定义或默认默认构造函数的类),该对象是零初始化的,然后它是默认的 - 如果它有一个非平凡的默认构造函数,则初始化;


3
投票

我很好吗?我的代码片段是否使用专门的分配器?

是的,没有分配器不专业。 std::vector<T>使用的默认分配器是std::allocator<T>。目前std::allocator<T>still specified to have a construct member做同样的事情。但这是一个弃用的成员。无论如何,即使将来完全删除它,通过std::allocator_traits的呼叫仍将表现相同。

[allocator.traits.members]

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

效果:如果调用格式良好,则调用a.construct(p, std​::​forward<Args>(args)...);否则,调用​::​new(static_­cast<void*>(p)) T(std​::​forward<Args>(args)...)

至于new T()做什么,你100%正确。


0
投票

我很好吗?

是。

我的代码片段是否使用专门的分配器?

不。您使用的是默认分配器std::allocator

我认为最后我的片段会调用新的T(),现在,根据https://stackoverflow.com/a/8280207,我认为a,b和c将为0,我是否正确?

正确。

© www.soinside.com 2019 - 2024. All rights reserved.