将临时对象作为对抽象的引用传递给构造函数

时间:2015-12-28 11:55:09

标签: c++ c++11

我的C ++上有点生疏,并且遇到了一些麻烦。

我有一个类,在示例grep . filename.txt 中,它为其构造函数引用了一个抽象类。理想情况下,我希望该类支持以下语法:

user

我有一个抽象类User u( Sub("") ); u.work(); ,其基类名为supersub类在其构造函数中引用了super。在运行时,user将临时引用传递给user

当调用sub时,我得到一个异常 - 因为临时解构了。 (奇怪的是,如果我删除u.work()super上的析构函数,我会得到不同的行为。

示例代码如下!

有没有办法解决这个问题?

我知道如果我接受更改签名并更改呼叫网站的语法,有很多方法,但我更喜欢保留呼叫签名:

sub

示例代码

User u( Sub("") );
u.work();

3 个答案:

答案 0 :(得分:4)

Sub("")这样的临时对象的生命周期在它出现的完整表达式的末尾结束,即以分号结束。

C ++不允许您将此类临时对象绑定到可变引用,但Microsoft的编译器确实允许这样做。尽管如此,从这样的临时值初始化类成员引用会立即生成一个悬空引用,您绝不能再使用它;在构造函数体外部进行评估会导致未定义的行为。

解决此问题的方法是不在您的班级中存储引用!

例如,如果您想要拥有多态值,则可以使用唯一指针:

 #include <memory>

 class User
 {
    std::unique_ptr<Super> s_;

 public:
    User(std::unique_ptr<Super> s) : s_(std::move(s)) {}

    void work() { s_->func(); }
 };

 User u(std::make_unique<Sub>("Hello"));
 u.work();

答案 1 :(得分:1)

您在各种尝试之间看到的差异都只是未定义行为中的事故。 SuperSub的结构只是一种分心。

您无法保留对临时的引用。

    User(Super& s) :
        super_(s)
...
    Super& super_;

传入初始化super_的引用必须是一个持续时间至少与super_一样长的对象。

  

我知道如果我接受更改签名,有很多方法   改变呼叫站点的语法,但我宁愿坚持   呼叫签名:

你离任何有效的设计都很远。但是如果你真的想传递,那么保持一个多态的临时对象,你可以将一个虚拟克隆方法放到Super中以支持类似的东西:

    User(Super& s) :
        super_(s.clone())
...
    std::unique_ptr<Super> super_;

答案 2 :(得分:0)

您的问题是Sub()的所有权。目前你创建它,参考它,然后它被破坏。

一种正确的方法可能是将指针传递给Sub to User,并让User获取所有权,保留Sub直到它不再需要Sub。这可能看起来像:

class User
{
     Super *super_;
public:
     User(Super *super)
        : super_(super)
     {
     }
     ~User()
     {
        delete super_;
     }
 };


User u( new Sub("") );