c + +与非平凡的类成员类型的联合?

问题描述

我正在与一个工会合作,该工会的成员是使用菱形继承的类,但是该程序在分配给该成员时遇到分段错误

我怀疑我需要添加一些副本构造函数,但是经过多次尝试,执行此操作的正确方法仍然使我不知所措。

我在此处提供了一个最小的,可重复的示例。

struct Base
{
    Base() : a(0) {}
    Base(int x) : a(x) {}

    int a;
};

struct Derived1 : virtual public Base
{
    Derived1() {}
};

struct Derived2 : virtual public Base
{
    Derived2() {}
};

struct Final : public Derived1,public Derived2
{
    Final() {}
};

union Example
{
    Final value;
    int i;
};

int main()
{
    Example example{ Final() };
    example.i = -1;

    /* Segfault on the line below. 
     * If the above line

       example.i = -1;
     
     * is removed,the segfault is not encountered. */

    example.value = Final();
}

我感谢所有知道该怎么做的人。

解决方法

由于@override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider( create: (ctx) => Authentication(),),ChangeNotifierProvider( create: (ctx) => Books(),ChangeNotifierProvider( create: (ctx) => HomeProvider(),ChangeNotifierProvider( create: (ctx) => Renk(),],child: MaterialApp( 类为virtual,因此很可能有些内部控制结构在分配时会被破坏

Base

例如,当您重新创建example.i = -1;

value

在分配之前,分段错误消失了。虽然,我不推荐这种黑客攻击。


正如注释中已经提到的,如果您有C ++ 17,那么std::variant会更合适。该示例将变为

new(&example.value) Final();
example.value = Final();
,

从c ++ 11开始,与定义自己的构造函数的成员进行联合 和/或复制控制成员是允许的,但是当一个联合具有内置类型的成员时,我们可以使用普通分配来 更改工会持有的价值,但不更改具有以下成员的工会的价值 非平凡的类类型。当我们将联盟的价值与成员之间进行切换时 类类型,我们必须构造或销毁该成员。例如看下面的代码

#include <iostream>
#include <new> // for placement new

class Type   // non built in type with constructors
{
private:
    int val;

public:
    Type() : val{0} {    }

    explicit Type(int v) : val{v}  {  }

    Type(const Type &obj) : val{obj.val} {  }

    int getval()  {   return val;  }
};

class unionexample   // I enclose union with class for readability
{
private:
    enum { INT,TYPE } OBJ;

    union
    {
        Type Tval;  // non build in type
        int ival;   // build in type
    };

public:
    unionexample() : ival{0},OBJ{INT} // default with int
    { }

    unionexample(const unionexample &obj) : OBJ{obj.OBJ}
    {
        switch (obj.OBJ)
        {
        case INT:
            this->ival = obj.ival;
            break;
        case TYPE:
            new (&this->Tval) Type(obj.Tval);
            break;
        }
    }

    unionexample &operator=(int v)
    {
        if (OBJ == TYPE)
        {
            Tval.~Type(); // if it is TYPE destruct it
        }

        ival = v; // assign

        OBJ = INT;

        return *this;
    }

    unionexample &operator=(Type v)
    {
        if (OBJ == TYPE)
        {
            Tval = v;  // if it is alderdy Type just assign
        }

        new (&Tval) Type(v); // else construct

        OBJ = TYPE;

        return *this;
    }

    void print()
    {
        switch (OBJ)
        {
        case INT:
            std::cout << "ival = " << ival << std::endl;
            break;

        case TYPE:
            std::cout << "Tval = " << Tval.getval() << std::endl;
            break;
        }
    }

    ~unionexample()
    {
        if (OBJ == TYPE)  // if it is TYPE we must destruct it
            Tval.~Type();
    }
};

int main()
{
    unionexample ue;
    ue.print();
    ue = Type(1);
    ue.print();
}

输出:

ival = 0
Tval = 1

Run Here

以您为例

int main()
{
    Example example{ value : Final() };     // construct with Final

    example.value.~Final();                 // destruct Final

    example.i = -1;                         // assign int built in type
    
    new(&example.value)  Final();           // construct
    
    example.value.~Final();                 // destruct finally
}

如果您不是出于学习目的问了这个问题,则可以像其他答案一样使用std::variant

谢谢。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...