c – std ::洗涤槽如何影响容器?

考虑以下简化和不完整的固定大小向量的实现:
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;

索引运算符使用起始指针来访问该对象.此时的对象被pop破坏,另一个对象通过push(2)在其存储位置创建.如果我正确地阅读了关于std::launder的文档,这意味着以下行中v [0]的行为是未定义的.

如何使用std :: launder来纠正这个代码?每次使用新产品时,我们是否必须开始和结束流水? stdlib的当前实现似乎使用类似于上面发布的代码.这些实现的行为是否未定义?

解决方法

如何使用std :: launder来纠正这个代码?每次使用新产品时,我们是否必须开始和结束流水?

P0532R0开始,您可以避免需要调用lawn(),如果将placement new的返回值分配给end.除非矢量为空,否则您不需要更改开始指针,因为由start指定的对象仍然具有您提供的代码的活动生命周期.

同一篇文章指出,除非对象生命周期已经结束并且已经被一个新的对象所替代,否则,洗牌()是无效的,所以如果没有必要,使用流水线不会导致性能损失:

[…] 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还讨论了这个问题,内容类似于问题评论中的讨论:向量不直接使用布局新,放置新调用的返回值在向量的分配器的函数链中丢失,并且在任何事件布局新的元素使用元素,所以构建内部向量机器不能使用返回值.洗衣()似乎是这里打算使用的工具.然而,由allocator指定的指针类型根本不需要是一个原始指针类型,而launder()只适用于原始指针.目前的实施方式目前尚未定义为某些类型;流氓()似乎不是用于解决基于分配器的容器的通用情况的适当机制.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...