微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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()只适用于原始指针.目前的实施方式目前尚未定义为某些类型;流氓()似乎不是用于解决基于分配器的容器的通用情况的适当机制.

原文地址:https://www.jb51.cc/c/113075.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐