我有两个班,Foo和Bar。 Bar维护对Foo的引用,并且具有调用Foo中的方法来改变其状态的方法。代码如下所示。
class Foo
{
private:
double m_value;
public:
void setValue(double value) {
this->m_value = value;
};
double getValue() {
return this->m_value;
};
};
class Bar
{
private:
Foo& m_foo;
public:
Bar() : m_foo(Foo()) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
当我在设置之后尝试访问foo的值时出现问题,如下所示:
Bar bar;
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
哪个输出Foo value is -9.25596e+061
。看来记忆已经腐败了 - 为什么?我知道不存储m_foo作为参考(即使用Foo m_foo;
)将解决问题,但我不明白为什么会这样。
更令人费解的是,在发布模式下运行时,上面的代码可以正常工作。
我正在使用Visual Studio 2010进行编译。
非常感谢提前!
答案 0 :(得分:2)
很少有编译器报告构造函数Bar()的错误。我在编译时遇到了以下错误,
在构造函数'Bar :: Bar()'中:非const的初始化无效 'Foo&amp;'类型的参考来自'Foo'类型的临时编译 由于-Wfatal-errors
而终止
Bar() : m_foo(Foo()) { };
在构造函数Bar中,Foo()返回在堆栈中创建的对象,其生命周期在构造函数返回时结束。因此,它的生命周期是暂时的,这将导致访问未定义的内存或悬挂引用。
解决方案1:按原样使用Foo对象,无需任何参考
class Bar
{
private:
Foo m_foo;
public:
Bar(){
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
解决方案2:将Foo对象作为参数传递给Bar构造函数,这将保持有效,直到main的范围。
class Bar
{
private:
Foo &m_foo;
public:
Bar(Foo &x) : m_foo(x) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
int main()
{
Foo x;
Bar bar(x);
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
}
答案 1 :(得分:1)
Bar() : m_foo(Foo())
您正尝试从lvalue-reference
初始化temporary
。你不应该做这样的事情。在最后一个括号之后 - 对象将被销毁,你将有悬空参考。
实际上,MSVC中存在非标准扩展,允许绑定临时对象引用。例如,gcc会为此类案例提供错误test here您也可以查看此答案rvalue to lvalue conversion Visual Studio。
答案 2 :(得分:1)
创建栏
时Bar() : m_foo(Foo()) {
};
您提供对新创建的foo实例的引用,该实例将超出范围,并在分配给m_foo后立即删除。这实际上是VS c编译器的缺陷,因为g ++会给你和这些代码的错误,你可以在这里看到。 http://liveworkspace.org/code/3kW04t $ 218