类型擦除是否有效取决于优化级别
Type erasure works or fails depending on optimization level
我正在尝试通过类型擦除(作为简单格式化文本输出库的一部分(将值类型包装在包装器中。下面print
的函数应该接受一个包装在类型擦除包装结构中的参数,该结构知道(通过函数指针(如何将其转换为字符串并打印它。
当我编译它时,它打印 0(有时是垃圾(:
g++ -std=c++11 -Wall -Wextra -O0 -o test test.cpp
但是当使用 -O1
到 -O3
进行编译时,它会按预期工作(-Og
也会失败(。使用 clang++,它的行为方式相反(启用优化时会失败(。我还尝试了 g++ -m32(我的 x86_64 Linux Mint 盒子上有 multilib gcc(和 32 位和 64 位 mingw-w64 交叉编译器。行为类似。此外,clang++-libc++似乎总是失败。
我必须触发一些未定义的行为(因为我发现 g++ 和 clang++ 不太可能有相同的错误(。这是怎么回事,我错过了什么?
#include <iostream>
#include <string>
using namespace std;
// Struct holding a pointer to a type-erased value and a function pointer to
// convert it to a string
struct TypeErasingWrapper {
void* item; // Pointer to type erased value
string (*to_string)(void*); // Function pointer to convert it to a string
};
// Convert any value pointer to a string (using the proper overload of
// std::to_string
template <typename T>
string toString (void* item)
{
return to_string(*reinterpret_cast<T*>(item));
}
// Wrap any value in a type-erasing wrapper
template <typename T>
TypeErasingWrapper wrap(T value) {
return {&value, toString<T>};
}
// Print a type erased value
void print(TypeErasingWrapper wrapper)
{
cout << wrapper.to_string(wrapper.item) << endl;
}
int main()
{
print(wrap(1234));
}
这是没有模板的版本,其行为方式相同。
#include <iostream>
#include <string>
using namespace std;
// Struct holding a pointer to a type-erased int and a function pointer to
// convert it to a string
struct TypeErasingWrapper {
void* item; // Pointer to type erased int
string (*to_string)(void*); // Function pointer to convert it to a string
};
// Convert type-erased int to a string
string toString (void* item)
{
return to_string(*reinterpret_cast<int*>(item));
}
// Wrap an int in a type-erasing wrapper
TypeErasingWrapper wrap(int value) {
return {&value, toString};
}
// Print a type erased value
void print(TypeErasingWrapper wrapper)
{
cout << wrapper.to_string(wrapper.item) << endl;
}
int main()
{
print(wrap(1234));
}
template <typename T>
TypeErasingWrapper wrap(T value) {
return {&value, toString<T>};
}
您按价值获取value
。 然后,将指向它的指针传递给返回值。
值value
仅持续到函数体结束,此时指针变为悬空指针。
更改TypeErasingWrapper
以存储void const*
。 更改wrap
以采取const&T
。 template<class T> std::string toString( void const * )
也是。 修复剩余的生成错误。 将reinterpret_cast
更改为static_cast
。
通常,类型擦除代码还会擦除所有权(销毁、移动,有时是复制(,以便处理生存期问题。 如果你不这样做,我建议调用你的类型blah_view
,以向最终用户表明它不是真正的值类型。
作为最后一条注释,请在文件范围内停止using namespace std;
。 简洁很少值得。
- 空基优化子对象的地址
- 关闭||运算符优化
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 重载运算符new[]的行为取决于析构函数
- 返回值优化:显式移动还是隐式
- 人脸跟踪arduino代码的优化
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 纯函数,为什么没有优化
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- 如何以优化的方式同时迭代两个间距不相等的数组
- 小字符串优化(调试与发布模式)
- 浮点定向舍入和优化
- Visual Studio 调试优化如何工作?
- 为什么开关的优化方式与 c/c++ 中的链接不同?
- 线性优化目标函数中的绝对值
- GCC 会优化内联访问器吗?
- gcc 如何优化此循环?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 类型擦除是否有效取决于优化级别
- 调试构建hello world崩溃,取决于优化水平