C++ 强制转换std::vector的一部分<;char>;到std::数组<;字符,n>;,c++;11
根据C++11标准,以下代码是否违反了严格的别名或导致未定义的行为?是否有更好的方法来实现相同的功能C++ 强制转换std::vector的一部分<;char>;到std::数组<;字符,n>;,c++;11,c++,c++11,C++,C++11,根据C++11标准,以下代码是否违反了严格的别名或导致未定义的行为?是否有更好的方法来实现相同的功能 void do_things(const std::array<char, 64> &block) { // ... } int main() { std::vector<char> buffer(64); do_things(reinterpret_cast<const std::array<char, 64> &
void do_things(const std::array<char, 64> &block) {
// ...
}
int main() {
std::vector<char> buffer(64);
do_things(reinterpret_cast<const std::array<char, 64> &>(buffer[0]));
}
根据我对别名的理解,这不应导致未定义的行为,并捕获传递固定大小数组的语义。我的理解正确吗?严格的别名规则涉及§3.10[basic.lval]/p10,其中规定 如果程序试图通过访问对象的存储值 行为为以下类型之一以外的glvalue 未定义:
- 对象的动态类型
- 对象动态类型的cv限定版本
- 与对象的动态类型类似的类型(如4.4中所定义)
- 与对象的动态类型相对应的有符号或无符号类型
- 一种类型,它是与对象的动态类型的cv限定版本相对应的有符号或无符号类型
- 在其元素或非静态数据成员中包含上述类型之一的聚合或联合类型(包括, 递归地,子集合或子集合的元素或非静态数据成员 (包含的联合)
- [……]
std::array
的glvalue访问类型为char
的对象不会违反此规则,因为std::array
是一种聚合类型,它包括char
作为非静态子聚合数据成员的元素
但是,由于不同的规则-§9.3.1[class.mfct.non static]/p2: 如果为对象调用类
X
的非静态成员函数
这不是X
类型,也不是从行为X
派生的类型
没有定义
还值得注意的是,标准中没有任何规则保证sizeof(std::array)==sizeof(T)*N
。标准唯一能保证的是,std::array
是一种聚合类型,可以使用包含多达N
T
s的带括号的init列表对其进行初始化。实现可以自由添加额外的内容
根据所需的操作,您可能希望让函数使用随机访问迭代器,或者只使用一个指针。或者,如果您希望将函数限制为只接受std::vector
和std::array
s,则可以编写重载,将常量引用带到这些函数,并调用执行实际工作的助手函数
新版本并没有打破我能想到的任何规则,但它的设计相当糟糕,要求几乎每次调用函数时都要使用reinterpret\u cast
。如果您意外地将buffer
声明为std::vector
,或编写了buffer
而不是buffer[0]
,编译器将在没有警告的情况下愉快地编译您的代码,有潜在的灾难性后果。相关:有什么理由不编写基于迭代器的通用解决方案吗?当然,这会打破严格的别名。此外,std::array
甚至不能保证除了元素之外没有其他数据成员…@HerpDerpington仅供参考,随机访问迭代器不能保证连续存储。提供这样的迭代器,例如,没有这样的连续存储保证。但是,如果您可以使用随机访问迭代器,那么基于迭代器的解决方案上的SFINAE启用策略就足够了。值得思考。@HerpDerpington它必须是一个聚合,并且您必须能够使用数组a={initializer list}初始化它代码>如果初始值设定项列表最多为N
逗号分隔T
s。但是没有规则规定实现不能放入额外的内容。std::vector
保证连续内存(如果您需要的话)。§9.3.1[class.mfct.non static]/p2冲突发生,因为索引std::数组调用运算符[],对吗?@HerpDerpington正确。
void do_things(const char (&block)[64]) {
// ...
}
int main() {
std::vector<char> buffer(64);
do_things(reinterpret_cast<char (&)[64]>(buffer[0]));
}