我的C ++上有点生疏,并且遇到了一些麻烦。
我有一个类,在示例grep . filename.txt
中,它为其构造函数引用了一个抽象类。理想情况下,我希望该类支持以下语法:
user
我有一个抽象类User u( Sub("") );
u.work();
,其基类名为super
。 sub
类在其构造函数中引用了super。在运行时,user
将临时引用传递给user
。
当调用sub
时,我得到一个异常 - 因为临时解构了。 (奇怪的是,如果我删除u.work()
和super
上的析构函数,我会得到不同的行为。
示例代码如下!
有没有办法解决这个问题?
我知道如果我接受更改签名并更改呼叫网站的语法,有很多方法,但我更喜欢保留呼叫签名:
sub
示例代码
User u( Sub("") );
u.work();
答案 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)
您在各种尝试之间看到的差异都只是未定义行为中的事故。 Super
和Sub
的结构只是一种分心。
您无法保留对临时的引用。
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("") );