【问题标题】:Return an object that contains another object from a function从函数返回一个包含另一个对象的对象
【发布时间】:2018-12-29 07:24:47
【问题描述】:

为什么第一次调用cout后drawManifestoGlobal中的值会发生变化?看起来 canvas.panel.drawManifestoGlobal 被破坏了 - 为什么?

我该如何解决这个问题?

#include <iostream>

class DrawManifestoGlobal {
public:
    int value = 2;
};

class Panel {
public:
    void setDrawManifestoGlobal(DrawManifestoGlobal & _drawManifestoGlobal);
    DrawManifestoGlobal * drawManifestoGlobal;
};

class Canvas {
public:
    Canvas() {};
    Canvas(DrawManifestoGlobal _drawManifestoGlobal);
    DrawManifestoGlobal drawManifestoGlobal;
    Panel panel;
};


class SerDe {
public:
    Canvas doSerDe();
};

Canvas SerDe::doSerDe() {

    DrawManifestoGlobal drawManifestoGlobal;
    drawManifestoGlobal.value = 99; 
    Canvas canvas(drawManifestoGlobal);

    return canvas;
}

Canvas::Canvas(DrawManifestoGlobal _drawManifestoGlobal) {
    drawManifestoGlobal = _drawManifestoGlobal;
    panel.setDrawManifestoGlobal(drawManifestoGlobal);
}

void Panel::setDrawManifestoGlobal(DrawManifestoGlobal &_drawManifestoGlobal) {
    drawManifestoGlobal = &_drawManifestoGlobal;
}

int main () {
    SerDe serde;
    Canvas canvas;
    canvas = serde.doSerDe();

    std::cout << canvas.panel.drawManifestoGlobal->value << std::endl; // prints 99
    std::cout << canvas.panel.drawManifestoGlobal->value << std::endl; // prints 0 (!!!)
}

关于实现要求:Canvas 拥有 Panel 和 DrawManifestoGlobal,并且 Panel 本身具有指向 Canvas 的 DrawManifestoGlobal 的指针,因此从 Canvas 发生的任何更改对 Panel 都是可见的。

【问题讨论】:

    标签: c++ function pointers object return


    【解决方案1】:

    为什么drawManifestoGlobal 中的值在第一次调用cout 后会发生变化?看起来 canvas.panel.drawManifestoGlobal 被破坏了 - 为什么?

    doSerDe() 函数内的drawManifesttoGlobal 是一个在作用域末尾过期的局部变量,但您正在设置指向它的指针 (Panel::drawManifestoGlobal) 并将指针传递到函数外部(通过canvas)。所以你有未定义的行为来访问一个已经被破坏的对象的值。编译器完全有权为同一个对象打印两个不同的值。

    如果你真的需要一个指针(你不需要),你会想要动态分配drawManifestoGlobal(最好使用unique_ptr)。

    class Panel {
    public:
      void setDrawManifestoGlobal(std::unique_ptr<DrawManifestoGlobal> _drawManifestoGlobal);
      std::unique_ptr<DrawManifestoGlobal> drawManifestoGlobal;
    };
    
    Canvas SerDe::doSerDe() {
      std::unique_ptr<DrawManifestoGlobal> drawManifestoGlobal(make_unique<DrawManifesttoGlobal>());
      drawManifestoGlobal.value = 99; 
      return {std::move(drawManifestoGlobal)};
    }
    
    void Panel::setDrawManifestoGlobal(std::unique_ptr<DrawManifestoGlobal> drawManifestoGlobal) {
      drawManifestoGlobal = std::move(_drawManifestoGlobal);
    }
    

    事实上,您的代码中的任何地方都不需要指针!

    【讨论】:

    • 感谢您的帮助! 1) 但是为什么 DrawManifestoGlobal 会被破坏呢?它在 Canvas 中创建,然后(一个副本)Canvas 被传递回 main。那个 Panel 和 DrawManifestoGlobal 不应该搭上顺风车吗? 2) 如果没有指针,Panel 的 DrawManifestoGlobal 的内部变量总是与 Canvas 的 DrawManifestoGlobal 中的值相同,有什么方法可以做到这一点?
    • @Saro 1) 它在Canvas 构造函数中创建,但它的生命周期与构造函数的主体相关联。在函数体结束后_drawManifesttoGlobal 被破坏,但你仍然有一个指向它的指针,你在构造函数之外(在 main 中)使用它。即使它是传递给 main 的 Canvas 的副本,也只会复制 Panel::drawManifestoGlobal 的内部 指针,而不是它指向的对象。 2)我不知道你希望它的内部变量是一样的。在这种情况下,您应该使用指针。
    猜你喜欢
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多