我今天遇到了一个非常微妙的问题,我想征求您的意见。
考虑以下花园式的共享体习语类:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
当您尝试按以下方式将它们放入 vector 时,乐趣就会出现:
std::vector<S> v(42);
现在,至少在 MSVC 8 中,
v
中的所有元素共享相同的 impl
成员。实际上,导致这种情况的原因是 vector
构造函数:template <typename T, typename A = ...>
class vector
{
vector(size_t n, const T& x = T(), const A& a = A());
...
};
在场景下,只有一个
S
对象被默认构造,从它复制 n
的 vector
元素。现在,在 C++11 中,有右值引用。所以它不能像这样工作。如果
vector
构造为std::vector<S> v(42);
那么很可能,实现将选择默认构造 vector 内的
n
对象,因为复制构造可能不可用。在这种情况下,这将是一个突破性的变化。我的问题是:
std::vector
必须具有如上定义的构造函数,即。使用默认参数?特别是是否保证 vector 对象的条目被复制而不是默认构造? PS:请不要评论上面
S
类的默认构造函数。就是这样或者实现了某种形式的惰性构造。 最佳答案
是的,指定的行为是 x
被复制 n
次,以便容器被初始化为包含 n
元素,这些元素都是 x
的拷贝。
在 C++11 中,这个构造函数已经变成了两个构造函数。
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n); // (2)
除了它不再有第二个参数的默认参数这一事实外, (1) 的工作方式与在 C++03 中的工作方式相同:
x
被复制 0x2313413 次。代替
n
的默认参数,添加了 (2) 。此构造函数值初始化容器中的 x
个元素。不制作任何拷贝。如果您需要旧行为,则可以通过向构造函数调用提供第二个参数来确保调用 (1) :
std::vector<S> v(42, S());
是的,正如您的示例所示,这确实是一个突破性的变化。
由于我不是 C++ 标准化委员会的成员(并且我没有特别密切关注邮件中与库相关的论文),我不知道讨论了这种重大更改的程度。
关于c++ - std::vector、默认构造、C++11 和重大更改,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5759232/