std::string 实现是否符合其中 's.c_str() + s.size()' 不一定与 '&s[s.size()]' 相同?
Is a std::string implementation conformant where 's.c_str() + s.size()' is not necessarily the same as '&s[s.size()]'?
§21.4.5 [string.access]
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
如果为
pos < size()
,则返回:*(begin() + pos)
。否则,返回对类型为charT
、值为charT()
的对象的引用,其中修改对象会导致未定义的行为。
第二部分至少对我来说意味着,这个"charT
类型的对象"可能位于std::string
对象中存储的序列之外。一致性operator[]
:的示例实现
reference operator[](size_type pos){
static contexpr charT default = charT();
if(pos == size())
return default;
return buf[pos];
}
现在,c_str()
/data()
是根据operator[]
:指定的
§21.4.7 [string.accessors]
const charT* c_str() const noexcept;
const charT* data() const noexcept;
返回:一个指针
p
,使p + i == &operator[](i)
用于[0,size()]
中的每个i
。
这将使上述operator[]
实现不一致,如p + size() != &operator[](size())
。然而,通过一些技巧,你可以绕过这个问题:
reference operator[](size_type pos){
static contexpr charT default = charT();
if(pos == size() && !evil_context) // assume 'volatile bool evil_context;'
return default;
return buf[pos];
}
struct evil_context_guard{
volatile bool& ctx;
evil_context_guard(volatile bool& b)
: ctx(b) {}
~evil_context_guard(){ b = false; }
};
const charT* c_str() const noexcept{
evil_context_guard g(evil_context = true);
// now, during the call to 'c_str()', the requirement above holds
// 'p + i == &operator[](i) for each i in [0,size()]'
const charT* p = &buf[0];
assert(p+size() == &operator[](size()));
return p;
}
现在,显而易见的问题是…
上面的代码真的符合吗?还是我忽略了什么
忽略给定的代码,只考虑问题,我认为
- 不幸的是,答案似乎是";是";,以及
- 这当然不是标准的意图
因此,它似乎是一个缺陷。
检查已知库缺陷的列表显然这个问题还没有报告。
因此,正如我在聊天中所说,我建议将其发布到[comp.std.c++],以解决它是否真的是缺陷的问题,如果是,则将其放入缺陷列表并修复。
我看不出它是如何一致的。用户代码永远无法遵守承诺的返回值。代码中的assert
具有误导性,因为它位于错误的位置:函数尚未返回返回:要求适用于从函数返回的值,而不是其实现中的某个值(应该很清楚为什么这是一个荒谬的想法)。
断言应该在这里:
auto p = s.c_str();
assert(p + s.size() == &operator[](s.size()));
我相信专门对待s[s.size()]
的措辞只是为了禁止你炸毁空终止符。
相关文章:
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么 GCC 不能假设 std::vector::size 在这个循环中不会改变?
- C++数组输入不接受一定数量的整数
- C++|以一种很好的方式将树(不一定是二进制的)打印到stdout
- 当我的阵列达到一定大小时,Qt 不起作用
- 不一定获得成员价值的 getter 方法?
- 为什么会出现错误:size不是std的成员
- 大小 N 和 N 的所有排列不一定等于数组的大小
- 如何将我的C 程序分为包含普通代码行的文件,不一定功能
- 迭代器的继任者不一定是常规功能:如何可能
- 为什么 std::array::size 不是静态的?
- 为什么 std::list.size() 不是恒定时间?
- 为什么"volatileQualifiedExpr + volatileQualifiedExpr"不一定是 C 中的 UB 而是C++中的 UB?
- std::string 实现是否符合其中 's.c_str() + s.size()' 不一定与 '&s[s.size()]' 相同?
- 如果我只想要架构良好的工作区,但不一定是分开的编译,如何在C++中组织头/代码文件
- C++ "new T[size]"不起作用?
- 如果通过指针分配,C++ vector.size() 不会更新
- c++ set size不对应于它的元素个数
- 为什么size不是std::initializer_list的模板参数?
- 检查字符串是否按顺序包含子字符串的字符序列,但不一定紧挨着