【问题标题】:Scope of object in an array数组中对象的范围
【发布时间】:2011-11-03 02:16:45
【问题描述】:

假设您在 C++ 中有一个对象数组,并且您从数组中删除了其中一个对象。什么时候调用该对象的析构函数?由于 C++ 没有自动垃圾收集,因此如果在从数组中删除后立即调用析构函数,这似乎很奇怪。但是在数组超出范围之前,对象是否保持分配状态?这似乎会导致内存泄漏。

编辑:

如何将数组的元素之一设置为不同的对象,而不是“删除”。

另外,当一个元素从std::vector 中移除时会发生什么

【问题讨论】:

  • 您不能从数组中“删除”对象。你是在说std::vector吗?
  • 请说明您认为从数组中删除项目的方式。
  • 如何移除对象?这些对象是动态分配在堆上还是栈上的数组?
  • @domonic 假设它是堆栈上的一个数组。我知道如果它们是动态分配的,我将不得不删除它们以释放内存。
  • 好的,在这种情况下,您可能对copy and swap idiom 感兴趣。

标签: c++ memory-leaks destructor


【解决方案1】:

您不能“从数组中删除其中一个对象”。数组具有固定大小。所有的内容都是在创建数组的时候构造的,在数组本身销毁的时候销毁。

如果您只是为数组元素分配一个新值,那么您正在调用对象的= 运算符,它的行为与您有一个简单的独立变量并为其分配一个新值没有什么不同。没有对象必须被构造或销毁。如果有任何新对象,它来自编译器为赋值语句右侧生成的临时对象。语句完成后,临时对象被销毁。数组中的对象保持不变。

当您从 vector 中删除一个项目时,它的析构函数会被调用,正如您所期望的那样,后面的元素会向下移动以填补空白。

【讨论】:

    【解决方案2】:

    当你声明一个 C++ 数组时,它会构造堆栈上的所有对象,并且它们会一直留在那里直到数组本身被删除:

    std::string ArrayOfStrings[10]; //There are now ten strings here
    

    不能从这种数组中“删除”对象。当 ArrayOfStrings 超出范围时,它会自动删除数组中的所有字符串。如果您编辑此数组中的对象,则该对象本身会更改。你实际上改变了字符串本身,而不是一些指针或引用。

    如果你有一个指针数组,那么 C++ 会构造所有指针,但你必须自己管理它们指向的内容:

    std::string* ArrayOfPointersToStrings[10];
    

    您可以手动删除数组中指针指向的字符串,但您必须自己完成所有这些操作。当 ArrayOfPointersToStrings 超出范围时,它不会删除字符串指向的任何内容。如果你编辑一个指针而不先删除它,那就是内存泄漏,这很糟糕。

    如果你有一个 std::vector,C++ 只根据你的构造方式构造一些对象:

    std::vector<std::string> VectorOfStrings(10);
    

    这将创建一个 动态 字符串数组。可以从向量中删除对象,在这种情况下,向量会立即将其删除并为您重新排列其余部分。如果您编辑此数组中的对象,则该对象本身会更改。你实际上改变了字符串本身,而不是一些指针或引用。

    澄清cmets:

    char *myLiteral = "APPLE";
    //"APPLE" is an immutable string, myLiteral points at it.
    std::string s= myLiteral; 
    std::string t = myLiteral;
    //s and t each makes a _seperate_ _mutable_ copy of "APPLE"
    s[3] = '?'; 
    //s is now "APP?E", because we just changed the L.  NO COPY WAS DONE. 
    std::cout << t[3];
    //displays "L", because t's copy was never changed.
    

    【讨论】:

    • 但是 std::string 不是不可变的吗?
    • @Daniel: string s = "hello"; s = "world"; s 的值现在是 "world"codepad.org/a8B4SoWM
    • 另外,如果您执行std::string *a; *a = "hello"; 之类的操作,则不必手动删除 a。
    • @Bill 我知道,但那是因为创建了一个包含字符“world”的新字符串对象。
    • a) 是的,你必须delete a;。 b) 它是同一个对象,只是使用(可能)不同的内部缓冲区来存储文本。
    【解决方案3】:

    您不能从普通 C++ 数组中删除对象。当您声明一个特定大小的数组时,无论是在堆栈还是堆上,假设分配成功,都会分配足够的内存来创建该类型的 N 个对象,并且它们是使用适当的构造函数创建的。

    使用赋值运算符将 RHS 的内容复制到数组中的对象通常对 RHS 上的对象没有任何作用。数组中的内存刚刚被覆盖。不会创建或删除任何新对象(除非您执行类似obj1 = obj2 = obj3 之类的操作,这是一个完整的“另一罐蠕虫......)

    【讨论】:

      【解决方案4】:

      对于像std::vector 这样的标准容器,当 remove 方法完成时,对象已被破坏。

      对于“c 样式”数组,对象本身的持续时间与不在数组中时一样长。

      对象的生命周期取决于分配对象的位置。如果它在堆栈上,它会在当前作用域结束时被释放,如果它在堆上,那么在调用delete 之前它不会被释放。如果对象从未被释放,最后一种情况会导致内存泄漏。

      【讨论】:

      • 如果我有一个数组,我替换其中的一个元素会发生什么。例如:a[0] = myObject();a[0] = myOtherObject();` myObject 实例何时被破坏?
      • @Daniel,myObject 实例在被 myOtherObject 实例覆盖时将被销毁。
      猜你喜欢
      • 2021-01-10
      • 2017-01-02
      • 2012-01-25
      • 1970-01-01
      • 2015-02-17
      • 2019-05-01
      • 2016-09-20
      • 1970-01-01
      • 2011-04-25
      相关资源
      最近更新 更多