【问题标题】:placement new in a (virtual) parent class在(虚拟)父类中放置新的
【发布时间】:2019-07-29 14:36:16
【问题描述】:

我有这个 CRTP:

template <class T>
struct S {
  void clear() { new (this) T; }
};

class SS : public S<SS> {
  int i = 5;
};

int main() {
  SS s;
  s.clear();
}

clear() 是否保证按预期工作? S 是不是虚拟的还有关系吗?

就此而言,我们可以假设所有继承 S 的类除了原始类型或 POD 类型之外什么都没有,因此没有花哨的构造函数和析构函数。

我用 gcc 和 valgrind 编译似乎没有抱怨,但感觉很奇怪。

【问题讨论】:

    标签: c++ crtp


    【解决方案1】:

    要在内存中的正确位置重新创建子类型,您必须强制转换 this 指针。

    另外,如果你不调用析构函数,你必须断言该类型是可简单破坏的:

    template <class T>
    struct S {
        void clear() {
            static_assert(std::is_base_of_v<S, T>);
            static_assert(std::is_trivially_destructible_v<T>);
            new (static_cast<T*>(this)) T;
        }
    };
    

    Valgrind 没有发出任何警告,因为基类中的 this 与派生类相同,因此您没有覆盖分配的任何内存。

    【讨论】:

    • 很好,谢谢。 static_cast 的意义何在?它可以改变 this 的实际值吗?
    • @user2717954 是的。 this 指针可以指向基类或派生类,因为它们在内存中的偏移量可能不同,具体取决于它们的内容或是否使用多重继承
    • 跟进问题。 std::is_trivially_destructible 要求 T 的析构函数不是虚拟的。如果 S 是虚拟的,是否有一些解决方法?
    • 或者即使 SS(继承 S 的类)是虚拟的,而 S 本身不是
    • @user2717954 是的,它不能是虚拟的。如果你想要一个非平凡的或虚拟的析构函数,你必须在创建新对象之前使用static_cast&lt;T*&gt;(this)-&gt;~T() 调用它
    【解决方案2】:

    除了static_cast&lt;T*&gt;(this),我还建议先在对象上调用dtor。

    template <class T>
    struct S {
        void clear() {
            auto this_ptr = static_cast<T*>(this)
            this_ptr->~T();
            new (this_ptr) T();
        }
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-04
      • 2012-08-15
      • 2012-02-04
      • 2018-06-12
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      • 2013-07-03
      相关资源
      最近更新 更多