【问题标题】:Creating objects in c++在 C++ 中创建对象
【发布时间】:2013-11-27 17:23:09
【问题描述】:

我只是在一条导致数据丢失的简单线路上浪费了几个小时。我有另一个类持有 MyClass 实例的向量。这个 AnotherClass 通过以下方式实例化 MyClass 的对象:

 AnotherClass::AnotherClass(){            
      MyClass myObject(...);
      myVector.push_back(&myObject);
 }

myObject 的地址随后被推入一个向量(与 MyClass 的其他实例一起),就像在代码中写的那样。当我开始使用 AnotherClass 的实例时,我注意到 MyClass 的值丢失了(完全随机)。当我将代码更改为:

 AnotherClass::AnotherClass(){            
      MyClass* myObject = new MyClass(...);
      myVector.push_back(myObject);
 }

我没有数据丢失。

谁能解释一下为什么第二种创建对象的方法不会导致数据丢失? (没有参考我 1.000 页的书)

【问题讨论】:

  • 存储指针而不是对象有什么特别的原因吗?如果没有,那就不要。
  • “我有 AnotherClass 持有 MyClass 实例的向量。” -- 不,你没有。或者如果你这样做了,它与这段代码无关,所以我不知道你为什么提到它。

标签: c++ object pointers instance instantiation


【解决方案1】:

简单。第一个版本在堆栈上创建一个局部变量,当它超出范围时(在函数末尾)自动销毁

您的向量只包含一个指向该对象曾经所在位置的指针。

第二个版本在堆上创建一个对象,直到你最终删除它为止。

【讨论】:

    【解决方案2】:

    原因是RAII

    在第一个 sn-p 中,您在方法/构造函数的范围内声明了一个对象。 一旦这个范围结束,当方法结束时,你的对象就会超出范围并为你清理(这意味着它的析构函数被调用)。你的向量现在仍然持有指向你已经清理过的无效对象的指针,这就是你得到垃圾的原因。

    在第二个 snippter 中,您的对象包含在堆中。除非您致电 delete myObj;,否则它们不会被清理/销毁。这就是为什么它们在方法结束后仍然有效的原因。

    您可以通过多种方式解决此问题:

    • 将你的向量声明为std::vector<MyClass>(注意,不是指针类型)
    • 保留第二个 sn-p,但确保在完成后删除矢量的所有元素
    • 如果您不想自己清理对象,请使用智能指针(例如 std::shared_ptrstd::unique_ptr

    【讨论】:

    • 感谢您提供信息丰富的答案和替代解决方案。所以` std::vector myVector; ` 和 ` myVector.push_back(MyClass myObject(...)); ` 将确保在我返回实例时保留信息?
    • 是的,但语法是 myVector.push_back(MyClass(...)); 。请注意,std::vector 的访问器方法返回引用。因此,当您推回对象时会创建一个副本,myVector[2] = foo; 之类的代码将修改向量内的元素,因为myVector[2]返回一个引用。
    【解决方案3】:

    第一种方式在堆栈上分配一个 MyClass 对象。该对象将在超出范围时被释放,即当构造函数运行时。

    第二种方式是在动态内存中分配对象。该对象将继续存在,直到您对其调用 delete。

    第二种方法是这样做的,但是您应该向 AnotherClass 添加一个析构函数,该析构函数遍历向量并删除所有对象。否则你的程序会有内存泄漏。

    【讨论】:

    • 感谢内存泄漏的警告,这可能是我要遇到的下一个问题 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多