我今天遇到了一个非常微妙的问题,我想听听你的意见。
考虑下面这个普通的共享主体成语类:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
有趣的是,当您尝试将这些向量放入向量时,请使用以下方法:
std::vector<S> v(42);
现在,至少在MSVC8中,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);
然后,最有可能的是,实现将选择缺省构造向量内的n
对象,因为复制构造可能不可用。在这种情况下,这将是一个突破性的变化。
我的问题是:
std::vector
必须有一个如上定义的构造函数,即。使用默认参数?特别是,是否可以保证复制矢量对象的条目而不是默认构造?PS:请不要评论上面类S
的默认构造函数。它就是这样或者实现了某种形式的惰性构造。
发布于 2011-04-23 03:35:01
是否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
元素。不会创建任何副本。
如果需要旧的行为,可以通过向构造函数调用提供第二个参数来确保调用(1):
std::vector<S> v(42, S());
我认为这是C++03和C++11之间发生重大变化的可能性。我认为这是C++03和C++11之间发生重大变化的可能性。这个问题已经调查过了吗?解决了吗?
是的,正如您的示例所示,这确实是一个突破性的变化。
由于我不是C++标准化委员会的成员(我也没有在邮件中特别关注与图书馆相关的论文),我不知道在多大程度上讨论了这一突破性的变化。
发布于 2012-03-02 06:42:39
我认为你描述的用例的解决方案不是最优的,也不是完整的,这就是为什么你在升级到C++11时遇到了问题。
C++总是关心语义,当你用c++编写程序时,你最好理解你的语义。因此,在您的示例中,您希望创建N个对象,但是当您没有更改它们时,您希望它们共享相同的内存以进行优化。好主意,但如何做到这一点: 1)复制构造函数。2)静态实现+复制构造函数。您是否考虑过这两种解决方案?
假设你需要N个对象的M个向量,如果你选择第一个场景,会分配多少次共享内存?它是M,但是如果我们想创建包含MxN对象的向量,为什么我们需要分配M次内存呢?
因此,这里正确实现是默认指向静态内存,并仅在对象发生更改时才分配内存。在这种情况下,分配N个对象的M个向量将为您提供...1“共享”内存分配。
在你的例子中,你违反了正确的语义滥用复制构造函数,那就是: 1)不明显,2)不是最优的,现在你必须付出代价。
https://stackoverflow.com/questions/5759232
复制相似问题