std::向量,默认结构,c++ 11和破坏变化

时间:2021-07-06 16:38:51

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:

我的问题是:

  1. 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 ?
  2. c++ 03标准是否要求std::vector必须具有如上定义的构造函数?使用默认参数?特别是,是否有一个保证,向量对象的条目会被复制而不是默认构造?
  3. What does the C++11 standard say about this same point ?
  4. 对于这一点,c++ 11标准怎么说?
  5. I see this as a possibility for a breaking change between C++03 and C+11. Has this issue been investigated ? Solved ?
  6. 我认为这是在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)不最佳,现在您必须付出代价。