const 向量无法修改,因为它是 const 对象。所以插入、追加、删除都是不允许的。然而,它的内容不是该对象的一部分,而是由该对象拥有。举个类似的例子:
int* const p = new int[10]{1,2,3,4};
Run Code Online (Sandbox Code Playgroud)
p是一个 const 对象,拥有可以修改的非常量数据:p[1]=5;
Vector 的operator[]条件是向量是否为 const,如果是,则返回 aconst int&但如果基础值不是 const,则删除 const 的 const 强制转换应该是合法的。
为了测试这一点,我编写了以下程序:
#include <vector>
constexpr int foo()
{
const std::vector<int> v{ 1,2,3 };
const int a[3]{ 1,2,3 };
*const_cast<int*>(&v[1]) = 21;
// However, this should fail and does on GCC and CLANG
//*const_cast<int*>(&a[1]) = 21;
return v[1];
}
int main()
{
constexpr int sb21 = foo();
const std::vector<int> v{ 1,2,3 };
*const_cast<int*>(&v[1]) = 21;
return v[1] + sb21;
}
Run Code Online (Sandbox Code Playgroud)
MSVC、CLANG 和 GCC 都可以编译和执行。
该代码在编译时计算 constexpr 函数。编译器应该在 UB 上产生编译时错误。为了进行比较,如果包含 const 元素的数组未注释,Clang 和 GCC 都会按预期产生错误。然而,MSVC 却没有,这似乎是一个错误。
用例具有固定大小的向量,其结构不能改变,但可以更新内容。
std::vector<T>使用std::allocator<T>,只要 的库实现vector不使用像std::string的短字符串优化这样的小尺寸,那么这应该是定义的行为。
下面的示例显示了const std::string存储在对象内的小字符串如何显示 UB,而分配的较长字符串则不然:
#include <string>
consteval int foo()
{
const std::string v{ "1234" };
//const std::string v{ "123412341234123412341234" };
*const_cast<char*>(&v[1]) = 'A';
return v[1];
}
int main()
{
return foo();
}
Run Code Online (Sandbox Code Playgroud)
这是定义的行为还是编译器没有标记 UB?
\n\n但如果底层值不是 const,那么删除 const 的 const 转换应该是合法的。
\n
这是你的论点的弱点。重要的不是潜在的价值,而是所拥有的对象。如果拥有的对象不是对象const,则删除强制转换应该是合法的。但是,你能证明所拥有的对象不是吗const?
我相信你不能。以您自己的示例为例, \xe2\x80\x93 是一个包含三个ints 的向量。假设每个int为 4 个字节,那么总数据为 12 个字节。还假设向量的大小为 24 字节(允许指针、大小和容量各占 8 字节)。int进行一点优化并将这三个s 存储在向量本身中,并加上一个标志来表示数据位于向量内部而不是动态分配(类似的方法用于短字符串优化),这并不是不合理的。中使用了类似的方法),
现在我们有可能数据位于向量本身内部,我们也有可能数据是const对象的一部分,因为向量是const。抛弃这种const改变值的特性是未定义的行为。
最重要的是,如果您不拥有该对象,您就无法确定它是如何创建的。如果主人告诉你它是const,那么你必须将其视为const。
| 归档时间: |
|
| 查看次数: |
979 次 |
| 最近记录: |