I ran today against a quite subtle issue I'd like to have your opinion on.
我今天遇到一个非常微妙的问题,我想听听你的意见。
Consider the following garden-variety shared-body-idiom class:
考虑一下下面的“普通”的“共享”类:
struct S
{
S() : p_impl(new impl) {}
private:
struct impl;
boost::shared_ptr<impl> p_impl;
};
The fun appears when you try to put those into vectors in the following way:
当你试着用下面的方法把它们放到向量中时,有趣的事情就出现了:
std::vector<S> v(42);
Now, with MSVC 8 at least, all the elements in v
share the same impl
member. Actually, what causes this is the vector
constructor:
现在,至少有了MSVC 8, v中的所有元素都有相同的impl成员。实际上,造成这种情况的是向量构造函数:
template <typename T, typename A = ...>
class vector
{
vector(size_t n, const T& x = T(), const A& a = A());
...
};
Under the scenes, only one S
object gets default constructed, the n
elements of the vector
are copied from it.
在场景下,只有一个S对象被默认构造,矢量的n个元素被复制。
Now, with C++11, there are rvalue references. So it cannot work like this. If a vector
is constructed as
现在,有了c++ 11,就有了rvalue引用。所以它不能这样工作。如果一个向量被构造为
std::vector<S> v(42);
then most likely, implementations will chose to default construct the n
objects inside the vector, since copy construction may not be available. This would be a breaking change in this case.
然后,大多数情况下,实现将选择默认构造矢量内的n个对象,因为复制构造可能不可用。在这种情况下,这将是一个巨大的改变。
My question is:
我的问题是:
- Does the C++03 standard mandates that
std::vector
must have a constructor defined as above, ie. with a default argument ? In particular is there a guarantee that the entries of the vector object get copied instead of default constructed ? - c++ 03标准是否要求std::vector必须具有如上定义的构造函数?使用默认参数?特别是,是否有一个保证,向量对象的条目会被复制而不是默认构造?
- What does the C++11 standard say about this same point ?
- 对于这一点,c++ 11标准怎么说?
- I see this as a possibility for a breaking change between C++03 and C+11. Has this issue been investigated ? Solved ?
- 我认为这是在C++03和C+11之间发生断裂的可能性。这个问题已经调查过了吗?解决了吗?
PS: Please no comments about the default constructor of the class S
above. It was this or implementing some form of lazy construction.
请不要对上面类S的默认构造函数有任何评论。就是这样或者实现了某种形式的惰性构建。
2 个解决方案
#1
46
Does the C++03 standard mandate that
std::vector
must have a constructor defined as above, i.e. with a default argument? In particular is there a guarantee that the entries of the vector object get copied instead of default constructed?c++ 03的标准要求std::vector必须有一个构造函数定义在上面,也就是带有默认参数的构造函数吗?特别是,是否有一个保证,向量对象的条目会被复制而不是默认构造?
Yes, the specified behavior is that x
is copied n
times so that the container is initialized to contain with n
elements that are all copies of x
.
是的,指定的行为是x被复制n次,因此容器被初始化为包含n个元素,这些元素都是x的拷贝。
What does the C++11 Standard say about this same point?
对于这一点,c++ 11标准怎么说?
In C++11 this constructor has been turned into two constructors.
在c++ 11中,这个构造函数已经被转换为两个构造函数。
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n); // (2)
Except for the fact that it no longer has a default argument for the second parameter, (1) works the same way as it does in C++03: x
is copied n
times.
除了它不再为第二个参数设置默认参数之外,(1)与在c++ 03中所做的工作方式相同:x被复制n次。
In lieu of the default argument for x
, (2) has been added. This constructor value-initializes n
elements in the container. No copies are made.
(2)代替了x的默认参数。这个构造函数值初始化容器中的n个元素。没有副本。
If you require the old behavior, you can ensure that (1) is called by providing a second argument to the constructor invocation:
如果您需要旧的行为,您可以通过向构造函数调用提供第二个参数来确保调用(1):
std::vector<S> v(42, S());
I see this as a possibility for a breaking change between C++03 and C++11. I see this as a possibility for a breaking change between C++03 and C++11. Has this issue been investigated? Solved?
我认为这是在c++ 03和c++ 11之间发生重大变化的可能性。我认为这是在c++ 03和c++ 11之间发生重大变化的可能性。这个问题已经调查过了吗?解决了吗?
Yes, as your example demonstrates, this is indeed a breaking change.
是的,正如您的例子所示,这确实是一个突破性的变化。
As I am not a member of the C++ standardization committee (and I haven't paid particularly close attention to library-related papers in the mailings), I don't know to what degree this breaking change was discussed.
由于我不是c++标准化委员会的成员(而且我在邮件中也没有特别关注图书馆相关的文件),我不知道这个突破性的变更讨论到了什么程度。
#2
-3
I think solution for use-case you described is not optimal and not complete, that's why you got problems upgrading to C++11.
我认为您描述的用例的解决方案不是最佳的,也不完整,这就是为什么您在升级到c++ 11时遇到了问题。
C++ always cares about semantic and when you write program in c++ you'd better to understand your semantic. So in your case you wish to create N objects, but while you are not changing them you wish them to share same memory for optimization. Nice idea, but how to get this done: 1) copy constructor. 2) static implementation + copy constructor. Have you considered both solutions?
c++总是关注语义,当你用c++编写程序时,你最好理解你的语义。在这种情况下,你希望创建N个对象,但是当你不改变它们的时候,你希望它们共享相同的内存以进行优化。好主意,但如何完成:1)复制构造函数。2)静态实现+复制构造函数。你考虑过这两种解决方案吗?
Consider you need M vectors of N objects, how many times shared memory will be allocated if you choose 1st scenario? It is M, but why do we need to allocate memory M times if we want to create vectors containing MxN objects?
假设你需要N个对象的M个向量,如果你选择第一个场景,会分配多少次共享内存?它是M,但是如果我们想要创建包含MxN对象的向量,为什么我们需要分配内存M乘以?
So correct implementation here is to point to static memory by default, and allocate memory only if object is changed. In such a case allocating M vectors of N objects will give you... 1 'shared' memory allocation.
因此,这里的正确实现是在默认情况下指向静态内存,并仅在对象发生更改时分配内存。在这种情况下,分配N个对象的M个向量会得到。1“共享的内存分配。
In your case you violated correct semantic abusing copy constructor, which is: 1) not obvious 2) not optimal and now you have to pay off.
在您的例子中,您违反了正确的语义滥用复制构造函数,即:1)不明显2)不最佳,现在您必须付出代价。
#1
46
Does the C++03 standard mandate that
std::vector
must have a constructor defined as above, i.e. with a default argument? In particular is there a guarantee that the entries of the vector object get copied instead of default constructed?c++ 03的标准要求std::vector必须有一个构造函数定义在上面,也就是带有默认参数的构造函数吗?特别是,是否有一个保证,向量对象的条目会被复制而不是默认构造?
Yes, the specified behavior is that x
is copied n
times so that the container is initialized to contain with n
elements that are all copies of x
.
是的,指定的行为是x被复制n次,因此容器被初始化为包含n个元素,这些元素都是x的拷贝。
What does the C++11 Standard say about this same point?
对于这一点,c++ 11标准怎么说?
In C++11 this constructor has been turned into two constructors.
在c++ 11中,这个构造函数已经被转换为两个构造函数。
vector(size_type n, const T& x, const Allocator& = Allocator()); // (1)
explicit vector(size_type n); // (2)
Except for the fact that it no longer has a default argument for the second parameter, (1) works the same way as it does in C++03: x
is copied n
times.
除了它不再为第二个参数设置默认参数之外,(1)与在c++ 03中所做的工作方式相同:x被复制n次。
In lieu of the default argument for x
, (2) has been added. This constructor value-initializes n
elements in the container. No copies are made.
(2)代替了x的默认参数。这个构造函数值初始化容器中的n个元素。没有副本。
If you require the old behavior, you can ensure that (1) is called by providing a second argument to the constructor invocation:
如果您需要旧的行为,您可以通过向构造函数调用提供第二个参数来确保调用(1):
std::vector<S> v(42, S());
I see this as a possibility for a breaking change between C++03 and C++11. I see this as a possibility for a breaking change between C++03 and C++11. Has this issue been investigated? Solved?
我认为这是在c++ 03和c++ 11之间发生重大变化的可能性。我认为这是在c++ 03和c++ 11之间发生重大变化的可能性。这个问题已经调查过了吗?解决了吗?
Yes, as your example demonstrates, this is indeed a breaking change.
是的,正如您的例子所示,这确实是一个突破性的变化。
As I am not a member of the C++ standardization committee (and I haven't paid particularly close attention to library-related papers in the mailings), I don't know to what degree this breaking change was discussed.
由于我不是c++标准化委员会的成员(而且我在邮件中也没有特别关注图书馆相关的文件),我不知道这个突破性的变更讨论到了什么程度。
#2
-3
I think solution for use-case you described is not optimal and not complete, that's why you got problems upgrading to C++11.
我认为您描述的用例的解决方案不是最佳的,也不完整,这就是为什么您在升级到c++ 11时遇到了问题。
C++ always cares about semantic and when you write program in c++ you'd better to understand your semantic. So in your case you wish to create N objects, but while you are not changing them you wish them to share same memory for optimization. Nice idea, but how to get this done: 1) copy constructor. 2) static implementation + copy constructor. Have you considered both solutions?
c++总是关注语义,当你用c++编写程序时,你最好理解你的语义。在这种情况下,你希望创建N个对象,但是当你不改变它们的时候,你希望它们共享相同的内存以进行优化。好主意,但如何完成:1)复制构造函数。2)静态实现+复制构造函数。你考虑过这两种解决方案吗?
Consider you need M vectors of N objects, how many times shared memory will be allocated if you choose 1st scenario? It is M, but why do we need to allocate memory M times if we want to create vectors containing MxN objects?
假设你需要N个对象的M个向量,如果你选择第一个场景,会分配多少次共享内存?它是M,但是如果我们想要创建包含MxN对象的向量,为什么我们需要分配内存M乘以?
So correct implementation here is to point to static memory by default, and allocate memory only if object is changed. In such a case allocating M vectors of N objects will give you... 1 'shared' memory allocation.
因此,这里的正确实现是在默认情况下指向静态内存,并仅在对象发生更改时分配内存。在这种情况下,分配N个对象的M个向量会得到。1“共享的内存分配。
In your case you violated correct semantic abusing copy constructor, which is: 1) not obvious 2) not optimal and now you have to pay off.
在您的例子中,您违反了正确的语义滥用复制构造函数,即:1)不明显2)不最佳,现在您必须付出代价。