正确使用new/delete

Proper use of new/delete

本文关键字:delete new      更新时间:2023-10-16

作为我上一个问题的续集,我想问一下我在下面的代码中做错了什么。

代码为,例如

void myclass1::myfun()
{
myclass2* newVar = new myclass2();
/* other code and stuff */
myvector.push_back(newVar); // myvector is a member of myclass1 and is a std::vector<myclass2*>
delete newVar;
}

但是当我运行它时,myvector返回空,除非我注释掉delete行。

我做错了什么?

您只希望在完全使用完对象后删除它。一旦你删除了它,你就不应该试图再次引用它。

在典型情况下,您只想将对象本身(而不是指向对象的指针)放入vector中。这将在将对象添加到vector时创建该对象的副本,并在从vector中删除该对象或vector本身被销毁时自动销毁该对象。

如前所述,当您已经释放内存时,您无法访问或更改内存。必须注意在析构函数(或额外的函数)中删除对象。下面是这样做的代码片段:

// this function adds the object
`void MyClass1::AddFun()
{
  myClass2* Ptr = new myClass2();  // create new object via new-operator
  myvector.push_back(Ptr);
}
// this function clears the entire vector
void MyClass1::ClearAllContent()
{
  while (myvector.empty() == false)
  {
    delete myvector[myvectory.size() - 1];  // free the last object in your vector
    myvector.pop_back();                    // pop_back reomves the "empty"-pointer
  }
}

调用newVar的析构函数,并在调用delete时将new分配的内存返回给堆。

此时不应该调用delete。在myclass1的析构函数或其他成员函数中执行。

最佳实践是:存储在vector值或智能指针中,如boost::shared_ptr<>。智能指针适合你的情况。你甚至不用担心删除myvector的元素,因为当myvector被解构时,它们会被正确地解构。示例代码为:

void myclass1::myfun()
{
   myvector.push_back(boost::shared_ptr<myclass2>(new myclass2()));
}

c++不是c#或Java或其他什么。您正在使用原始指针,您可能不应该这样做。当您删除刚刚分配的对象时,它就消失了,不能再使用了。在vector中存储指向它的指针,而该指针似乎在函数作用域之外持续存在,这是一个错误。

您在堆上创建了myclass2的实例,然后将指向它的指针放入向量中。当你执行delete newVar;时,你正在破坏你刚刚创建的实例。但是你的vector仍然有一个指向对象所在位置的指针,而这个指针已经失效了。

当你不再需要堆上的对象时,你应该只调用delete

选项如下:

  1. 不要删除对象。这意味着你必须在程序的其他地方删除它,当所有的东西都用完了。这可能很难协调,所以你需要使用智能指针。如果您正在编译c++0x,则可以在Boost库或标准库中找到shared_ptr。下面是在c++0x中如何使用它:

    #include <vector>
    #include <memory>
    #include <algorithm>
    #include <iostream>
    int main(int argc, const char* argv[]) {
      typedef std::vector<std::shared_ptr<int>> Vector;
      Vector v = {
        Vector::value_type(new int(2)),
        Vector::value_type(new int(5))
      };
      std::for_each(v.begin(), v.end(), [](Vector::value_type x) {
        std::cout << *x << std::endl;
      });
      return 0;
    }
    
  2. 不要在堆上分配对象。相反,只需用myclass的实例填充向量,而不是指向myclass的指针。现在你的矢量将是std::vector<myclass2>

如果可以选择,第二个选项是最好的。当vector被销毁时,myclass2的实例将被销毁,这就减少了跟踪它们的麻烦。