无法使用C ++中的unique_ptr返回派生类型

时间:2017-04-19 02:08:48

标签: c++ stl segmentation-fault polymorphism unique-ptr

我收到了一个奇怪的错误。当我尝试在返回指向基类型的唯一指针的函数中返回指向派生类型的唯一指针时,就好像返回值降级为基类型一样。我无法访问它的任何方法或成员,如果我尝试,程序段错误。

如果我尝试将e1重新分配给返回类型并调用其“eval”方法,则以下示例为segfaults。奇怪的是,在返回之前调用eval方法可以正常工作。当我使用赋值变量作为函数的参数之一时似乎会发生这种情况,因为创建一个新对象来存储返回类型确实有效。

不幸的是,我的算法需要像这样的行:

e1 = create( *e1, *e2 );

请参阅下面的完整代码:

#include <memory>
#include <iostream>

class expr
{
public:
    virtual int eval() = 0;
    virtual ~expr() = default;
};

class add_expr : public expr
{
    expr& e1;
    expr& e2;
public:
    add_expr( expr& e1, expr& e2 ): e1(e1), e2(e2) {}
    int eval(){ return e1.eval() + e2.eval(); }
};

class int_expr : public expr
{
    int value;
public:
    int_expr( int value ) : value(value) {}
    int eval(){ return value; }
};

std::unique_ptr<expr> create( expr& ast1, expr& ast2 );

int main()
{
    auto e1 = std::unique_ptr<expr>( new int_expr( 10 ) );
    auto e2 = std::unique_ptr<expr>( new int_expr( 10 ) );
    e1 = create( *e1, *e2 );

    // this seg faults
    std::cout << e1->eval() << '\n';

    // this works properly
    auto e3 = create( *e1, *e2 );
    e3->eval();
    return 0;
}

std::unique_ptr<expr> create( expr& ast1, expr& ast2 )
{
    auto r = std::unique_ptr<expr>( new add_expr( ast1, ast2 ) );

    // this works properly
    std::cout << r->eval() << '\n';
    return r;
}

注意:我知道这个例子很荒谬,它只是一个非常大的程序的统一形式。

1 个答案:

答案 0 :(得分:0)

在这一行:

e1 = create( *e1, *e2 );

您重新分配e1。这意味着e1过去指向的内容(int_expr)被删除(因为它是unique_ptr)。

现在,e1指向的新内容(add_expr)仍然保留对刚被删除的int_expr的引用。当它尝试使用对已删除对象的引用时,它会遇到未定义的行为,在您的情况下会遇到段错误。