Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用具有唯一\u ptr的并集_C++_C++11_Struct_Unions_Unique Ptr - Fatal编程技术网

C++ 使用具有唯一\u ptr的并集

C++ 使用具有唯一\u ptr的并集,c++,c++11,struct,unions,unique-ptr,C++,C++11,Struct,Unions,Unique Ptr,当我尝试std::move或std::make_unique时,试图在联合内部使用唯一的_ptr会给我一个segfault #include <iostream> #include <memory> union myUnion{ struct{std::unique_ptr<float> upFloat;}structUpFloat; struct{std::unique_ptr<int> upInt;}structUpInt;

当我尝试std::move或std::make_unique时,试图在联合内部使用唯一的_ptr会给我一个segfault

#include <iostream>
#include <memory>

union myUnion{
    struct{std::unique_ptr<float> upFloat;}structUpFloat;
    struct{std::unique_ptr<int> upInt;}structUpInt;
    myUnion(){}
    ~myUnion(){}
};
struct myStruct{
    int x;
    myUnion num;

};
int main()
{
    myStruct aStruct, bStruct;
    aStruct.x = 1;
    bStruct.x = 2;

    auto upF = std::make_unique<float>(3.14);
    auto upI = std::make_unique<int>(3);

    aStruct.num.structUpFloat.upFloat = std::move(upF);
    bStruct.num.structUpInt.upInt = std::move(upI);

    std::cout << "aStruct float = " << *aStruct.num.structUpFloat.upFloat << std::endl;
    std::cout << "bStruct int = " << *bStruct.num.structUpInt.upInt << std::endl;
    return 0;
}
#包括
#包括
我的联盟{
结构{std::unique_ptr upFloat;}structurupfloat;
结构{std::unique_ptr upInt;}structUpInt;
myUnion(){}
~myUnion(){}
};
结构myStruct{
int x;
粘虫;
};
int main()
{
我的结构,结构;
aStruct.x=1;
b结构x=2;
自动upF=std::使_唯一(3.14);
自动upI=std::使_唯一(3);
aStruct.num.structurupfloat.upFloat=std::move(upF);
bStruct.num.structUpInt.upInt=std::move(upI);
标准::cout来自:

如果联合体包含一个非静态数据成员,该成员具有一个非平凡的特殊成员函数(复制/移动构造函数、复制/移动赋值或析构函数),则该函数在联合体中默认删除,并且需要由程序员显式定义

我假设您将指针包装在简单结构中的原因是,由于上面段落施加的限制,您无法以其他方式构建它


您所做的是绕过编译器安全卫士,可能在代码中有。

更改联盟的活动成员需要对对象生存期进行特殊的照顾。C++标准称(95p4):

注意:通常,必须使用显式析构函数调用和placement new运算符来更改活动的 工会会员

当成员是普通的旧数据时,它通常“只起作用”,即使您没有调用构造函数(使用placement
new
)和析构函数。这是因为具有简单初始化的对象的生存期从“获得足够大小和正确对齐的存储时”开始,而union提供了这一点

现在,您已经有了具有非平凡构造函数和析构函数的成员。它们的生存期不会从获取存储时开始,您还必须使初始化完成。这意味着新的位置。跳过析构函数调用也不安全,如果这些析构函数会对您的程序产生副作用,您将获得未定义的行为on(并且一个
unique_ptr
析构函数具有解除分配其目标的副作用)


因此,您正在对其生存期尚未开始的成员调用移动分配运算符。这是未定义的行为。

对于无限制的联合,您必须自己管理一些构造/销毁

以下可能会有所帮助:

union myUnion{
    std::unique_ptr<float> upFloat;
    std::unique_ptr<int> upInt;

    myUnion(){ new (&upFloat) std::unique_ptr<float>{};}
    ~myUnion() {}
};

class myStruct
{
public:
    ~myStruct()
    {
        destroy();
    }

    void destroy()
    {
        switch (type)
        {
            case unionType::f: num.upFloat.~unique_ptr<float>(); break;
            case unionType::i: num.upInt.~unique_ptr<int>(); break;
        }
    }

    void set(std::unique_ptr<int> p)
    {
        destroy();
        new (&num.upInt) std::unique_ptr<int>{std::move(p)};
        type = unionType::i;
    }
    void set(std::unique_ptr<float> p)
    {
        destroy();
        new (&num.upFloat) std::unique_ptr<float>{std::move(p)};
        type = unionType::f;
    }

public:
    enum class unionType {f, i} type = unionType::f; // match the default constructor of enum
    myUnion num;
};

int main()
{
    myStruct aStruct, bStruct;

    aStruct.set(std::make_unique<float>(3.14f));
    bStruct.set(std::make_unique<int>(3));

    std::cout << "aStruct float = " << *aStruct.num.upFloat << std::endl;
    std::cout << "bStruct int = " << *bStruct.num.upInt << std::endl;
    return 0;
}
union我的union{
std::唯一上浮;
std::唯一的\u ptr upInt;
myUnion(){new(&upFloat)std::unique_ptr{};}
~myUnion(){}
};
类myStruct
{
公众:
~myStruct()
{
破坏();
}
无效销毁()
{
开关(类型)
{
大小写unionType::f:num.upFloat.~unique_ptr();break;
大小写unionType::i:num.upInt.~unique_ptr();break;
}
}
无效集(标准::唯一\u ptr p)
{
破坏();
new(&num.upInt)std::unique_ptr{std::move(p)};
类型=联合类型::i;
}
无效集(标准::唯一\u ptr p)
{
破坏();
new(&num.upFloat)std::unique_ptr{std::move(p)};
类型=联合类型::f;
}
公众:
枚举类unionType{f,i}type=unionType::f;//匹配枚举的默认构造函数
粘虫;
};
int main()
{
我的结构,结构;
构造集(std::make_unique(3.14f));
b结构集(std::make_unique(3));

标准第12.6.2节【基础等级初始】/p8中的标准::cout(重点添加):

在非委托构造函数中,如果给定的非静态数据成员或 基类不是由 mem初始值设定项id(包括没有mem初始值设定项列表的情况,因为构造函数没有 并且实体不是抽象类(10.4)的虚拟基类,那么

  • 如果实体是具有大括号或相等初始值设定项的非静态数据成员,则按照8.5中的规定初始化实体
  • 否则,如果实体是变体成员(9.5),则不执行初始化
  • [……]
联合成员是变体成员,这意味着
unique\u ptr
s未初始化。特别是,没有调用构造函数,甚至没有调用默认构造函数。从技术上讲,这些
unique\u ptr
s的生存期甚至从未开始


unique\u ptr
move assignment操作符必须删除
unique\u ptr
当前保存的内容,但您将移动分配给未初始化的“
unique\u ptr
”包含垃圾值。因此,您的移动分配可能导致尝试删除垃圾指针,从而导致segfault。

如果两个指针指向同一个内存单元,它们是否仍然是唯一的?@πάνταῥεῖ 没有帮助/建设性或适用性。@Tuğrul我认为其中只有一个存在,或者至少有空间容纳最大的一个。我遗漏了什么吗?@πάνταῥεῖ: 不,调试器在这种严重破坏的情况下不会有帮助。调试器不会跟踪联合的活动成员。(事实上,仅在此类程序上使用调试器可能会导致未定义的行为,因为它将从非活动的联合成员读取)将它们包装到结构中来自更复杂的版本,我在这里简化了。删除这些包装仍然会产生可编译的代码。不,通过传递到这里。关于已删除的构造函数,您是对的,通过定义我自己的默认构造函数/析构函数,我传递了一个错误。我认为解决方案在cop中的某个地方y/assignment/move构造函数声明缺失,我一直无法找到。@jacksawild:您的问题与特殊成员没有太大关系——您没有在任何地方分配整个联合。它与变量成员的生存期有关。如果使用匿名联合,使整个class a变体(类联轴节)cla
#include <memory>
#include <iostream>
#include <vector>
struct myStruct
{
public:
    union
    {
        std::unique_ptr<float> upFloat;
        std::unique_ptr<int> upInt;
    };
    enum class unionType {f, i,none} type = unionType::none; // Keep it sane
    myStruct(){}
    myStruct(std::unique_ptr<float> p)
    {
        new (&upFloat) std::unique_ptr<float>{std::move(p)};
        type = unionType::f;
    }
    myStruct(std::unique_ptr<int> p)
    {
        new (&upInt) std::unique_ptr<int>{std::move(p)};
        type = unionType::i;
    }
    ~myStruct()
    {
        switch (type)
        {
            case unionType::f: upFloat.~unique_ptr<float>(); break;
            case unionType::i: upInt.~unique_ptr<int>(); break;
        }
    }
};

int main()
{
    std::vector<std::unique_ptr<myStruct>> structVec;
    structVec.push_back(std::make_unique<myStruct>(std::make_unique<float>(3.14f)));
    structVec.push_back(std::make_unique<myStruct>(std::make_unique<int>(739)));
    structVec.push_back(std::make_unique<myStruct>());
    structVec.push_back(std::make_unique<myStruct>(std::make_unique<float>(8.95f)));
    structVec.push_back(std::make_unique<myStruct>(std::make_unique<int>(3)));
    structVec.push_back(std::make_unique<myStruct>());

    for(auto &a: structVec)
    {
        if(a->type == myStruct::unionType::none)
        {
            std::cout << "Struct Has Unallocated Union" << std::endl;
        }
        else if(a->type == myStruct::unionType::f)
        {
            std::cout << "Struct float = " << *a->upFloat << std::endl;
        }
        else
        {
            std::cout << "Struct int = " << *a->upInt << std::endl;
        }
        std::cout << std::endl;
    }

    return 0;
}
union myUnion{
    std::unique_ptr<float> upFloat;
    std::unique_ptr<int> upInt;

    myUnion(){ new (&upFloat) std::unique_ptr<float>{};}
    ~myUnion() {}
};

class myStruct
{
public:
    ~myStruct()
    {
        destroy();
    }

    void destroy()
    {
        switch (type)
        {
            case unionType::f: num.upFloat.~unique_ptr<float>(); break;
            case unionType::i: num.upInt.~unique_ptr<int>(); break;
        }
    }

    void set(std::unique_ptr<int> p)
    {
        destroy();
        new (&num.upInt) std::unique_ptr<int>{std::move(p)};
        type = unionType::i;
    }
    void set(std::unique_ptr<float> p)
    {
        destroy();
        new (&num.upFloat) std::unique_ptr<float>{std::move(p)};
        type = unionType::f;
    }

public:
    enum class unionType {f, i} type = unionType::f; // match the default constructor of enum
    myUnion num;
};

int main()
{
    myStruct aStruct, bStruct;

    aStruct.set(std::make_unique<float>(3.14f));
    bStruct.set(std::make_unique<int>(3));

    std::cout << "aStruct float = " << *aStruct.num.upFloat << std::endl;
    std::cout << "bStruct int = " << *bStruct.num.upInt << std::endl;
    return 0;
}