std :: launder如何影响容器? [英] How does std::launder affect containers?

查看:81
本文介绍了std :: launder如何影响容器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下简单且不完整的固定大小向量的实现:

Consider the following, simplified and incomplete, implementation of a fixed-sized vector:

template<typename T>
class Vec {
  T *start, *end;

public:
  T& operator[](ssize_t idx) { return start[idx]; }

  void pop() {
    end--;
    end->~T();
  }

  template<typename... U>
  void push(U... args) {
    new (end) T { std::forward<U>(args)... };
    end++;
  }
};

现在考虑以下T:

struct T {
  const int i;
};

以及以下用例:

Vec<T> v;
v.push(1);
std::cout << v[0].i;
v.pop();
v.push(2);
std::cout << v[0].i;

索引运算符使用 start 指针指向访问对象。此时的对象被 pop 销毁,另一个对象由 push(2)在其存储位置中创建。如果我正确阅读了有关 std :: launder 的文档,则表示以下行中 v [0] 的行为是不确定的。

The index operator uses the start pointer to access the object. The object at that point was destroyed by pop and another object was created in its storage location by push(2). If I read the documentation surrounding std::launder correctly, this means that the behavior of v[0] in the line below is undefined.

应该如何使用std :: launder来更正此代码?每次使用新的刊登位置时,我们都必须洗头吗? stdlib的当前实现似乎正在使用类似于上面发布的代码。这些实现的行为是不确定的吗?

How is std::launder supposed to be used to correct this code? Do we have to launder start and end each time placement new is used? Current implementations of the stdlib seem to be using code similar to the one posted above. Is the behavior of these implementations undefined?

推荐答案

std :: launder code>应该用来更正此代码吗?

How is std::launder supposed to be used to correct this code? Do we have to launder start and end each time placement new is used?

来自 P0532R0 ,您可以避免调用 launder()(如果展示位置new的返回值分配给 end )。除非向量为空,否则您无需更改起始指针,因为 start 当前指向的对象在您提供的代码中仍然具有有效的生命期。

From P0532R0, you could avoid needing to call launder() if the return value of placement new is assigned to end. You would not need to change your start pointer unless the vector was empty since the object currently pointed to by start would still have an active lifetime with the code you provided.

同一篇论文指出 launder()是空操作,除非对象生存期已结束并且已被替换为新对象,因此如果不需要使用 launder()不会造成性能损失:

The same paper indicates that launder() is a no-op unless the object lifetime has ended and has been replaced with a new object, so using launder() will not incur a performance penalty if it is unnecessary:


[...] std :: launder(this)的类型等同于此,正如Richard Smith指出的那样:请记住, launder(p)是空操作,除非p指向寿命已到期且在同一存储中创建了新对象的对象。

[...] the type of std::launder(this) is equivalent to just this as Richard Smith pointed out: Remember that launder(p) is a no-op unless p points to an object whose lifetime has ended and where a new object has been created in the same storage.

当前stdlib的实现似乎使用的代码类似于上面发布的代码。这些实现的行为是不确定的吗?

是。 P0532R0 也讨论了此问题,内容类似于问题注释中的讨论: vector 不直接使用placement new,placement new调用的返回值在对函数的调用链中丢失向量的分配器,并且在任何情况下都逐个使用new,因此构造内部向量机制无论如何都不能使用返回值。 launder()似乎是打算在此处使用的工具。但是,分配器指定的指针类型完全不需要是原始指针类型,并且 launder()仅适用于原始指针。当前对于某些类型尚未定义当前实现; launder()似乎不是解决基于分配器的容器的一般情况的适当机制。

Yes. P0532R0 also discusses this issue and the content is similar to the discussion in the question's comments: vector does not use placement new directly, the return value of the placement new call is lost in the chain of function calls to the vector's allocator, and in any event placement new is used element by element so constructing the internal vector machinery cannot use the return value anyway. launder() appears to be the tool intended to be used here. However, the pointer type specified by the allocator is not required to be a raw pointer type at all and launder() only works for raw pointers. The current implementation is currently undefined for some types; launder() does not seem to be the appropriate machinery for solving the generic case for allocator based containers.

这篇关于std :: launder如何影响容器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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