std::vector,默认构造,c++ 11和破坏性变化
std::vector, default construction, C++11 and breaking changes
我今天遇到了一个很微妙的问题,我想听听你的意见。
考虑下面这个普通的共享体成语类:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
当你试着用下面的方式把它们变成向量时,有趣的事情就出现了:
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
对象被默认构造,vector
的n
元素从它复制。
现在,在c++ 11中,有右值引用。所以它不能这样工作。如果vector
被构造为
std::vector<S> v(42);
则很可能,实现将选择在vector内部默认构造n
对象,因为复制构造可能不可用。在这种情况下,这将是一个突破性的变化。
- c++ 03标准是否强制要求
std::vector
必须有一个如上定义的构造函数?使用默认参数?特别是,是否有一个保证,向量对象的条目被复制,而不是默认构造? c++ 11标准对这一点有什么规定? - 我认为这可能是c++ 03和c++ 11之间的突破性变化。这个问题调查过了吗?解决?
PS:请不要对上面的类S
的默认构造函数进行注释。
c++ 03标准是否要求
std::vector
必须有一个如上定义的构造函数,即带有默认实参?特别是有一个保证,向量对象的条目得到复制,而不是默认构造?
是的,指定的行为是将x
复制n
次,以便容器初始化为包含n
元素,这些元素都是x
的副本。
c++ 11标准对这一点有什么规定?
在c++ 11中,这个构造函数变成了两个构造函数。
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n); // (2)
(1)的工作方式与c++ 03中的相同:x
被复制n
次。
代替x
的默认参数,添加了(2)。这个构造函数对容器中的n
元素进行值初始化。不复制。
std::vector<S> v(42, S());
我认为这可能是c++ 03和c++ 11之间的一个重大变化。我认为这可能是c++ 03和c++ 11之间的一个重大变化。这个问题调查过了吗?解决了吗?
是的,正如你的例子所示,这确实是一个突破性的变化。
由于我不是c++标准化委员会的成员(我也没有特别关注邮件中与库相关的论文),我不知道这个突破性的变化讨论到了什么程度。
我认为您描述的用例解决方案不是最佳的,也不是完整的,这就是为什么您在升级到c++ 11时遇到问题的原因。
c++总是关心语义,当你用c++写程序时,你最好理解你的语义。因此,在您的情况下,您希望创建N个对象,但在不更改它们的同时,您希望它们共享相同的内存以进行优化。好主意,但如何做到这一点:复制构造函数。2)静态实现+复制构造函数。你考虑过这两种解决方案吗?
考虑您需要N个对象的M个向量,如果您选择第一种方案,将分配多少次共享内存?它是M,但是如果我们想要创建包含MxN个对象的向量,为什么我们需要分配内存M次?
所以这里的正确实现是默认指向静态内存,并且只在对象改变时才分配内存。在这种情况下,分配N个对象的M个向量会给你…"共享"内存分配。
在你的例子中,你违反了正确的语义滥用复制构造函数,这是:1)不明显2)不优现在你要付出代价了