【问题标题】:Can I keep vector data even after out of scope即使超出范围,我可以保留矢量数据吗
【发布时间】:2019-11-27 13:40:42
【问题描述】:

我来自 C 背景。我曾经分配内存/数组,例如,将其发送到其他地方,并且指针仍然保留在那里,即使在分配它的范围被破坏之后也是如此。

现在,如果我对向量执行相同的操作:初始化,通过引用传递它,然后将该引用保存在某处。在实际创建向量的初始方法超出范围之后,它会被销毁吗?或者因为指向它的指针仍然被保存,所以它会被保留。

【问题讨论】:

  • 通常“当引用绑定到临时对象或其子对象时,临时对象的生命周期会延长以匹配引用的生命周期”。请参阅:en.cppreference.com/w/cpp/language/reference_initialization.
  • @vahancho 在这里使用“通常”这个词要非常小心。事实上,它没有发生的次数超过了它发生的次数。

标签: c++ vector allocation


【解决方案1】:

std::vector 在销毁时释放它持有的内存。持有对被破坏的对象的引用是非常糟糕的。访问它是UB。一般规则:不要存储引用,仅在可以确定对象在整个范围内都存在的情况下使用它们,例如作为函数的参数。

如果您想保留数据的副本,只需复制std::vector。无需参考。

如果您希望能够从不同位置访问数据,并且只要至少一个位置仍然有一个引用/指针,就可以让它存在,不要使用std::vector,使用std::shared_ptr

如果您想将std::vector 的好处与共享内存的好处结合起来,直到最后一个地方放开它,请将它们结合起来:std::shared_ptr<std::vector<...>>

如果您想让std::vector 在一个地方住一段时间,然后再住到另一个地方但不再是原来的地方,请使用移动语义

std::vector<int> foo = {1, 2, 3};
std::vector<int> bar = std::move(foo); // bar now holds the data that foo held, foo is empty, no copy was performed

【讨论】:

  • 谢谢.. 这回答了我的问题.. 在 C 中我也没有真正分配数组本身,而是共享内存并使用数组语法来访问它。这可以通过 std::shared_ptr<:vector>> 我假设
  • 旁注:'method' 是 Java 术语,C++ 不知道该术语...
  • @Aconcagua 谢谢!我讨厌的 Java 过去每次都让我着迷 ^^
【解决方案2】:

指向堆栈上的数组的指针不会使数组保持活动状态,我想在 C 中也是如此。现在向量不是数组。它是堆分配数组的包装器,当它超出范围时释放数组的内存。

...因为指向它的指针仍然被保存,它仍然会被保留?

不!指向std::vector 的指针或引用不会使向量保持活动状态。典型的错误示例是:

std::vector<T>& foo() {
    std::vector<T> x;
    return x;
}                      // baaam !

从函数返回的引用是悬空的。你不能用它做任何事情。正确的做法是按值返回,依靠返回值优化:

std::vector<T> foo() {
    std::vector<T> x;
    return x;
}

如果你这样做:

auto y = foo();

感谢 NRVO,不涉及复制。

PS:编译器应该警告您返回对局部变量的引用。

【讨论】:

    【解决方案3】:

    不,如果我对向量做同样的事情,我会初始化一个向量,通过引用传递它,然后将引用保存在某个地方。在实际创建向量的初始方法超出范围后,它会被销毁吗?

    是的。

    或者因为指向它的指针仍然被保存,它仍然会被保留?

    没有。


    您可以在 C++ 中使用悬空指针,就像在 C 中一样。完全一样。

    引用也经常出现这种情况(尽管在某些情况下对象的生命周期会延长一点)。

    确实,向量的 data 是由向量在内部管理的,但这是顺便说一句,因为您询问的是向量本身。忘掉向量,就int 提出同样的问题,然后你会发现答案和你期望的一样。

    【讨论】:

      【解决方案4】:

      现有的答案很好,将在这里添加:

      block A
      {
      vector<int> my_vec(10, 0);
      //...something...
      }
      block B
      

      my_vec 向量将超出范围并在右括号处被销毁。现在是 stl(标准模板库)向量。

      您还可以使用 C 样式的数组(但使用不同的语法)。对于非常大的数组,我发现动态分配数组的分配时间比 STL 向量快。

      //static, goes out of scope and memory handled at the end of code block
      int arr0[10];
      
      //dynamic, not destroyed unless delete called.
      int* arr1 = new int[10];
      //...work with arr1...
      delete [] arr1;
      

      就像在 C 中一样,您需要注意取消分配您使用 new 创建的任何内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-16
        • 1970-01-01
        • 2018-10-13
        • 1970-01-01
        • 2020-03-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多