可以使用placement-new和vector :: data()来替换向量中的元素? [英] Can placement-new and vector::data() be used to replace elements in a vector?

查看:210
本文介绍了可以使用placement-new和vector :: data()来替换向量中的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关替换不可分配的向量元素的两个现有问题:

There are two existing questions about replacing vector elements that are not assignable:

  • C++ Use Unassignable Objects in Vector
  • How to push_back without operator=() for const members?

对象不可分配的一个典型原因是它的类定义包括 const 成员,因此已将 operator = 删除。

A typical reason for an object to be non-assignable is that its class definition includes const members and therefore has its operator= deleted.

std :: vector 要求其元素类型是可分配的。事实上,至少使用GCC,既不直接赋值( vec [i] = x; ),也不是 erase() insert()来替换元素,当对象不可分配时会工作。

std::vector requires that its element type be assignable. And indeed, at least using GCC, neither direct assignment (vec[i] = x;), nor a combination of erase() and insert() to replace an element works when the object is not assignable.

函数像下面这样使用 vector :: data(),直接元素销毁和放置新的复制构造函数,用于替换元素,而不会导致未定义的行为?

Can a function like the following, which uses vector::data(), direct element destruction, and placement new with the copy constructor, be used to replace the element without causing undefined behaviour?

template <typename T>
inline void replace(std::vector<T> &vec, const size_t pos, const T& src)
{
  T *p = vec.data() + pos;
  p->~T();
  new (p) T(src);
}

正在使用的函数示例如下。这在GCC 4.7中编译并似乎工作。

An example of the function in use is found below. This compiles in GCC 4.7 and appears to work.

struct A
{
  const int _i;
  A(const int &i):_i(i) {}
};

int main() {
  std::vector<A> vec;
  A c1(1);
  A c2(2);

  vec.push_back(c1);
  std::cout << vec[0]._i << std::endl;

  /* To replace the element in the vector
     we cannot use this: */
  //vec[0] = c2;

  /* Nor this: */
  //vec.erase(begin(vec));
  //vec.insert(begin(vec),c2);

  /* But this we can: */
  replace(vec,0,c2);
  std::cout << vec[0]._i << std::endl;

  return 0;
}


推荐答案

p7描述了使用析构函数调用和放置new来重新创建一个对象,指定对数据成员类型的限制:

This is illegal, because 3.8p7, which describes using a destructor call and placement new to recreate an object in place, specifies restrictions on the types of data members:


3.8对象生命周期[basic.life]



7 - 如果在对象的生命周期结束之后并且在对象占用的存储被重用或释放之前,是在原始对象占用的存储位置创建的,指向原始对象[...]的指针可以用
来操作新对象,如果:[...] b $ b - 原始对象[...]的类型不包含类型为const限定或引用类型[...]的任何非静态数据成员

3.8 Object lifetime [basic.life]

7 - If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object [...] can be used to manipulate the new object, if: [...]
— the type of the original object [...] does not contain any non-static data member whose type is const-qualified or a reference type [...]

因为你的对象包含一个const数据成员,在析构函数调用和放置之后,新的向量的内部数据指针在用于引用第一个元素时变得无效;我认为任何合理的阅读都会得出这样的结论,同样适用于其他元素。

So since your object contains a const data member, after the destructor call and placement new the vector's internal data pointer becomes invalid when used to refer to the first element; I think any sensible reading would conclude that the same applies to other elements as well.

这样做的理由是,优化器有权假设const和引用数据成员不分别修改或重置:

The justification for this is that the optimiser is entitled to assume that const and reference data members are not respectively modified or reseated:

struct A { const int i; int &j; };
int foo() {
    int x = 5;
    std::vector<A> v{{4, x}};
    bar(v);                      // opaque
    return v[0].i + v[0].j;      // optimised to `return 9;`
}

这篇关于可以使用placement-new和vector :: data()来替换向量中的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆