C++ 11使我们能够与非平凡成员创建匿名 union 。有时这可能非常有用-例如,如果我想为一些没有默认ctor的非平凡对象创建Holder类。
通过给它一个虚拟方法,使该NonTrivial对象更有趣:

#include <stdint.h>
#include <stdio.h>

struct Base
{
    virtual void something() { printf("something\n"); }
};

struct NonTrivial : Base
{
    explicit NonTrivial( int ) : a(1), b(2), c(3), d(4) { printf("NonTrivial\n"); }

    virtual void something() override { printf("something non trivial\n"); }

    int a;
    int b;
    int c;
    int d;
};

struct Holder
{
    Holder() : isNonTrivial(false), dummy(0x77) {}

    Holder( NonTrivial n) : isNonTrivial(true), nonTrivial( n ) {}

    bool isNonTrivial;
    union
    {
        int dummy;
        NonTrivial nonTrivial;
    };

    Holder & operator=( const Holder & rhs )
    {
        isNonTrivial = rhs.isNonTrivial;

        if( isNonTrivial )
            nonTrivial = rhs.nonTrivial;

        return *this;
    }
};

int main() {

    Holder holder_1;
    NonTrivial n(1);

    Holder holder_2( n );

    holder_1 = holder_2;

    holder_2.nonTrivial.something();
    holder_1.nonTrivial.something();

    return 0;

}

这样就行了。但是,这仅起作用是因为编译器实际上并未在此处进行虚拟调用。让我们强制它:
Base * ptr = &holder_1.nonTrivial;

ptr->something();

这会产生段错误。
但为什么?我或多或少做了明显的事情-检查是否持有人持有一个非平凡的对象,如果是-复制它。
阅读该程序集后,我看到此operator=实际上并未从rhs.nonTrivial复制vtable指针。我认为发生这种情况是因为NonTrivial的operator=应该只在完全构造的对象上调用,而完全构造的对象应该已经初始化了它的vtable指针-那么为什么还要打扰并复制它呢?

问题:
  • 我的想法正确吗?
  • operator=应该如何显示
    创建nonTrivial对象的完整拷贝?我有两个想法-删除
    整个operator=并强制用户使用复制ctor-或使用
    放置新位置,而不是nonTrivial = rhs.nonTrivial-但也许
    还有其他选择吗?

  • P.S.我知道std::optional之类的东西,我试图自己理解如何做。

    最佳答案

    如果有人偶然发现此问题以寻求快速解答,这就是我如何使用new位置解决此问题的方法:

    template< typename T, typename ... Args >
    void inplace_new( T & obj, Args && ... args )
    {
        auto * t = &obj;
    
        t = new(t) T{ args... };
    }
    
    Holder & operator=( const Holder & rhs )
    {
        isNonTrivial = rhs.isNonTrivial;
    
        if( isNonTrivial )
            inplace_new( nonTrivial, rhs.nonTrivial );
    
        return *this;
    }
    

    不要忘记#include <new> :)

    关于c++ - 如何使用虚拟方法编写与非平凡成员的匿名 union 的operator =,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52820803/

    10-15 05:49