转换为具有相同数据成员布局但实现不同的类是否安全?
Is it safe to cast to a class that has the same data member layout, but a different implementation?
第一个类将用于私有继承,以确保完全相同的布局。
#include <iostream>
#include <string>
struct data_base
{
data_base( int i, std::string&& s ) noexcept
: i_{ i }
, s_{ std::move( s ) }
{}
int i_;
std::string s_;
};
在这个简单的例子中,对于data<true>
的实例,我先打印int
数据成员,然后打印std::string
数据成员。
template<bool = true>
struct data : private data_base // inherits
{
data( int i, std::string&& s ) noexcept
: data_base( i, std::move( s ) )
{}
void print()
{
std::cout << "data<true> - " << i_ << s_ << 'n';
}
};
但是,data<false>
首先打印std::string
数据成员,然后是int
数据成员。
template<>
struct data<false> : private data_base
{
void print()
{
std::cout << "data<false> - " << s_ << i_ << 'n';
}
};
的例子:
int main()
{
data<true> d{ 5, "abc" };
d.print();
( ( data<false>& )d ).print();
}
演示:http://coliru.stacked-crooked.com/a/8b1262afe23dc0a2
如演示所示,即使打开了-fstrict-aliasing
标志,也没有警告。
现在,由于它们具有相同的布局,我认为我可以在这两种类型之间进行强制转换,以获得不同类型的静态多态性;没有虚函数调用的代价。
这个用法是安全的还是我触发了未定义的行为?
这或多或少就是这里所描述的,所谓的boost mutant习语。
据说(强调我的):
Boost突变习惯用法使用
reinterpret_cast
,并且在很大程度上依赖于具有相同数据成员(类型和顺序)的两个不同结构的内存布局是可互换的假设。虽然c++标准不保证这个属性,但实际上所有的编译器都满足它。此外,如果只使用POD类型,则变体习惯用法是标准的。
注:该页相当过时,我不知道最近的修订是否更改了保证上面提到的
From [expr.reinterpret.]在语言规范中,可以将引用从一种类型强制转换为另一种类型(如果可以将指针从一种类型强制转换为另一种类型)。
在你的类布局中,两种类型都有一个共同的基类来保存所有的数据。这两个派生类型不添加任何数据成员,也不添加任何虚函数,因此两个类的对象布局将是相同的。所以使用reinterpret_cast
是安全的。
在这种情况下,这类似于将基类的引用强制转换为另一个派生类的引用。
相关文章:
- 通过网络、跨平台传递std::变体是否安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 在函数结束后使用指向变量的指针是否安全?
- 逐字节删除 void* 是否安全?
- 在 RAII 构造中修改 RVO 值是否安全?
- 线程调用的函数对对象删除是否安全?
- 将对象的字节复制到数组并再次复制回来是否安全
- 使用枚举为数组编制索引是否安全?
- 返回从字符串文本创建的静态string_view是否安全?
- 在cstlib中将#include_next替换为#include是否安全
- 由并发无序映射查找线程调用的函数是否安全?
- 使用 c++ 原子时编写"y=++x"是否安全?
- 从另一个线程发出信号是否安全?
- 从其存储的回调中删除 std::函数是否安全
- 使用 std::vector::swap 方法在C++中交换两个不同的向量是否安全?
- 当我在C++中调用 struce 的只读静态成员时,线程是否安全
- 同时调用 ASIO 对象的 API 是否安全?
- 使用自己的迭代器分配容器是否安全?