提问者:小点点

自定义可选打破严格的别名规则


我编写了一个自定义的可选类(因为我被迫使用没有STL的C++98)。 它看起来是这样的:

template <typename T>
struct optional {
    char value[sizeof(T)];
    bool has_value;

    T& operator*() {
        return *reinterpret_cast<T*>(value);
    }
};

编译器产生警告取消引用类型双关语指针将打破严格的别名规则

我可以做什么使这个类没有UB? 也许应该使用memcpy,但我不明白如何使用。


共2个答案

匿名用户

避免警告的一种方法是使用类型识别工具。 即:

...
union {
   char empty;
   T value;
} storage;
bool has_value;
...

// when object is set to value
new (&storage.value) T(/* arg *);
has_value = true;

...
T& operator() {
   // check for has_value should be here
   return storage.value;
...

~optiona() {
   if (has_value) storage.value.~T();
...

这是可行的,因为当创建union时,第一个元素将被构造(空char)。 当您将value放入可选项中时,您将激活联合的第二个成员(value),并且自那时起可以很好地定义它来访问它。

匿名用户

我可以做什么使这个类没有UB?

  • 使用placement-new创建对象。
  • 可选
  • 的析构函数中调用所创建对象的析构函数
  • 注意对齐。 在C++11之前,这可能是相当棘手的。 您可能需要依赖非标准语言功能来实现这一点。
  • 不要重新解释存储地址。 使用从placement New返回的指针。 不幸的是,这意味着您需要将指针存储为成员。 您可以替换bool,因为null指针表示空状态。

动态分配对象会容易得多。 慢一点,是的。 但更简单和标准的一致性。