在Visual Studio调试模式下运行时,c ++对象引用已损坏

时间:2013-04-12 09:39:39

标签: c++ visual-c++

我有两个班,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进行编译。

非常感谢提前!

3 个答案:

答案 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