根据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> &>(buffer[0]));
}
Run Code Online (Sandbox Code Playgroud)
const char *
不那么痛苦编辑:既然sizeof(std::array<char, n>)
不能保证等于n
,我建议如下:
void do_things(const char (&block)[64]) {
// ...
}
int main() {
std::vector<char> buffer(64);
do_things(reinterpret_cast<char (&)[64]>(buffer[0]));
}
Run Code Online (Sandbox Code Playgroud)
根据我对别名的理解,这不应该导致未定义的行为并捕获传递固定大小的数组的语义.我的理解是否正确?
严格别名规则是指§3.10[basic.lval]/p10,它提供了这一点
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
- 对象的动态类型,
- 一个cv限定版本的动态类型的对象,
- 与对象的动态类型类似的类型(如4.4中所定义),
- 与对象的动态类型对应的有符号或无符号类型的类型,
- 一种类型,是有符号或无符号类型,对应于对象动态类型的cv限定版本,
- 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括递归地,子聚合或包含联合的元素或非静态数据成员)
- [...]
因此,通过类型char
的glvalue 访问类型的对象std::array<char, N>
不会破坏此规则,因为它std::array<char, N>
是包含char
非静态子聚合数据成员的元素的聚合类型.
但是,由于不同的规则,您仍然无法对结果引用执行任何有用的操作而不调用未定义的行为 - §9.3.1[class.mfct.non-static]/p2:
如果为非
X
类型的对象X
或派生类型的对象调用类的非静态成员函数X
,则行为未定义.
值得注意的是,标准中没有规则可以保证这一点sizeof(std::array<T, N>) == sizeof(T) * N
.标准保证的唯一内容std::array<T, N>
是聚合类型,可以使用包含最多s 的braced-init-list进行初始化N
T
.实现可以免费添加额外的东西.
根据do_things
需要,您可能希望使函数采用随机访问迭代器或简单的指针.或者,如果你想限制你的函数只使用std::vector
和std::array
s,你可以编写带有const引用的重载,并调用辅助函数const char *
来实现实际的工作.
新版本没有破坏我能想到的任何规则,但是reinterpret_cast
每次调用函数时都要求使用它是相当糟糕的设计.如果您不小心声明buffer
为a std::vector<std::string>
或编写buffer
而不是buffer[0]
编写代码,编译器将很乐意编译您的代码而不会发出警告,可能会带来灾难性的后果.
归档时间: |
|
查看次数: |
325 次 |
最近记录: |