首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >实现一个类似std::vector的容器,没有未定义的行为

实现一个类似std::vector的容器,没有未定义的行为
EN

Stack Overflow用户
提问于 2018-10-26 03:18:08
回答 1查看 700关注 0票数 6

这可能会让一些程序员感到惊讶,而且令人惊讶的是,如果没有编译器的非标准支持,就不可能实现std::vector。问题本质上在于在原始存储区域上执行指针算术的能力。这篇名为p0593: Implicit creation of objects for low-level object manipulation的论文出现在@ShafikYaghmour中,它清楚地暴露了这个问题,并提出了对标准的修改,以使向量容器和其他法律级别编程技术的实现变得更容易。

然而,我想知道是否没有办法实现一个等价于std::vector的类型,只使用语言提供的东西,而不使用任何标准库。

目标是在原始存储区域中一个接一个地构造向量元素,并能够使用迭代器访问这些元素。这相当于std::vector上的push_back序列。

为了了解这个问题,下面是对在libc++或libstdc++中实现std::vector所执行的操作的简化:

代码语言:javascript
复制
void access_value(std::string x);

std::string s1, s2, s3;
//allocation
auto p=static_cast<std::string*>(::operator new(10*sizeof(std::string)));

//push_back s1
new(p) std::string(s1);
access_value(*p);//undefined behavior, p is not a pointer to object

//push_back s2
new(p+1) std::string(s2);//undefined behavior
        //, pointer arithmetic but no array (neither implicit array of size 1)
access_value(*(p+1));//undefined behavior, p+1 is not a pointer to object

//push_back s2
new(p+2) std::string(s3);//undefined behavior
        //, pointer arithmetic but no array
access_value(*(p+2));//undefined behavior, p+2 is not a pointer to object

我的想法是使用一个从不初始化其成员的联合。

代码语言:javascript
复制
//almost trivialy default constructible
template<class T>
union atdc{
  char _c;
  T value;
  atdc ()noexcept{ }
  ~atdc(){}
};

原始存储将使用此联合类型的数组进行初始化,并始终在此数组上执行指针运算。然后在每个push_back处的联合的非活动成员上构造元素。

代码语言:javascript
复制
std::string s1, s2, s3;
auto p=::operator new(10*sizeof(std::string));
auto arr = new(p) atdc<std::string>[10];
//pointer arithmetic on arr is allowed

//push_back s1
new(&arr[0].value) std::string(s1); //union member activation
access_value(arr[0].value);

//push_back s2
new(&arr[1].value) std::string(s2);
access_value(arr[1].value);

//push_back s2
new(&arr[2].value) std::string(s2);
access_value(arr[2].value);

在上面的代码中是否有任何未定义的行为?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-26 04:00:18

这是正在积极讨论的话题,我们可以在proposal p0593: Implicit creation of objects for low-level object manipulation中看到这一点。这是对这些问题的一个非常坚实的讨论,以及为什么不进行更改就无法修复这些问题。如果您有不同的方法或对正在考虑的方法有强烈的看法,您可能想要联系提案的作者。

其中包括以下讨论:

2.3。数组的动态构造

考虑这个程序,它试图实现像std::vector这样的类型(为简洁起见,省略了许多细节):

……

在实践中,此代码适用于一系列现有的实现,但根据C++对象模型,未定义的行为发生在点#a、#b、#c、#d和#e处,因为它们试图在不包含数组对象的已分配存储区域上执行指针算法。

在位置#b、#c和#d,对char*执行算术,在位置#a、#e和#f,对T*执行算术。理想情况下,这个问题的解决方案将使两个计算都具有定义的行为。

  1. Approach

上述代码片段有一个共同的主题:它们试图使用它们从未创建过的对象。事实上,有一类类型,程序员认为他们不需要显式地创建对象。我们建议识别这些类型,并仔细制定规则,通过隐式创建来消除显式创建此类对象的需要。

使用adc联合的方法有一个问题,我们希望能够通过指针T*,即通过std::vector::data来访问包含的数据。将联合作为T*访问将违反strict aliasing rules,因此是未定义的行为。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52996590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档