gpt4 book ai didi

c++ - 为什么我的变体返回的值不等于分配的值?

转载 作者:行者123 更新时间:2023-12-01 15:13:22 26 4
gpt4 key购买 nike

我正在尝试创建一个简单的变体作为学习练习。

我想在不动态分配内存的情况下执行此操作,正如 std::variant 的 c++ 规范所指定的那样。 .

为简化起见,我的变体只能取两个值。

这是我的实现:

//variant style class for two types
template<typename T1, typename T2>
class Either {
using Bigest = std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>;
using ByteArray = std::array<std::byte, sizeof(Bigest)>;

ByteArray val;
std::optional<std::type_index> containedType;

public:

Either() : containedType(std::nullopt) {}

template<typename T>
Either(const T& actualVal) : containedType(typeid(T)) { //ToDo check T is one of correct types
ByteArray* ptr = (ByteArray*)&actualVal;
val = *ptr;
}

class BadVariantAccess {};

template<typename T>
inline T& getAs() const {
if(containedType == typeid(T)) {
T* ptr = (T*)val.data();
return *ptr;
}
else throw BadVariantAccess();
}
};

但是,当我对此进行测试时,我在尝试获取值后得到了一个不正确的数字:
int main() {

Either<int,float> e = 5;

std::cout << e.getAs<int>() << std::endl;

return 0;
}

返回一个随机数(例如 272469509)。

我的实现有什么问题,我该如何解决?

最佳答案

您的程序出于各种原因表现出未定义的行为,因此尝试解释您观察给定行为的原因有点毫无意义。但是您的代码存在一些严重问题:

  • 将任何内存别名为 std::array<std::byte, N> 是不安全的.这违反了严格别名规则,唯一的异常(exception)是指向 char 的指针。和 std::byte .当做ByteArray* ptr = (ByteArray*)&actualVal; val = *ptr; ,您正在调用 std::array's复制构造函数并传递一个不存在的实例。在这一点上,实际上任何事情都可能发生。相反,您应该一个接一个地复制字节(对于普通类型),或者使用放置 new在基于字节的存储中复制构造对象。
  • 您的存储未对齐,这可能会导致运行时崩溃或严重的性能损失,具体取决于您的目标平台。我不确定这是否会导致未定义行为,但如果您想继续进行这种低级内存管理,您当然应该解决这个问题。
  • 您的复制构造函数不会检查所分配类型的内存中的实际大小。如果在某个平台上,您有 sizeof(int) > sizeof(float) ,然后当您复制构建 Either<int, float>来自 float ,您将读取浮点数末尾的字节,并容易导致未定义行为。您必须考虑分配类型的大小
  • 如果您打算存储除普通类型以外的任何内容(即 std::stringstd::vector ,而不仅仅是原语),则需要调用适当的复制/移动构造函数/赋值运算符。对于构造函数(默认、移动、复制),您需要使用放置 new在预分配的存储中构造事件对象。此外,您需要使用类型删除来存储一些函数,这些函数会将包含的对象销毁为正确的类型。 std::function<void(std::byte*)> 中的 lambda在这里可能非常有用,它只是调用析构函数:[](std::byte* data){ (*reinterpret_cast<T*>(data)).~T(); }每当您存储新类型时,都必须分配它。请注意,这种情况几乎是您唯一一次想要手动调用析构函数。

  • 我强烈建议您仔细阅读有关如何正确进行此类低级内存管理的内容。做错事真的很容易,直到你很久以后才被奇怪的错误所困扰,才会有任何想法。

    正如@MilesBudnek 所指出的, using Biggest = std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>将给出类型特征,因此是 Biggest 的实例实际上将是结构 std::conditional 的特化的一个实例而不是 T1T2 .您的意思可能是 std::conditional_t<...>std::conditional<...>::type;这可能会影响您的 Either class 只会分配一个字节,这显然是不正确的。

    关于c++ - 为什么我的变体返回的值不等于分配的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60662440/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com