【问题标题】:Auto reference for vectors?向量的自动参考?
【发布时间】:2020-07-22 22:42:41
【问题描述】:

以下代码不会改变for循环中i的内容:

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        if (target == 0) {return vector<vector<int>>{{}};} 
        else if (!candidates.size() || target < 0) {return vector<vector<int>>();}
        else {
            vector<vector<int>> with = combinationSum(candidates, target - candidates[0]); 
            vector<int> new_vector(candidates.begin() + 1, candidates.end());
            vector<vector<int>> without = combinationSum(new_vector, target);
            for (auto i : with) {i.push_back(candidates[0]);}

            with.insert(with.end(), without.begin(), without.end());
            return with;
                                        
        }
    }
};

但是,如果我将其更改为 auto&amp; i : with ...,它可以工作。有什么原因吗?我认为只有在使用指向对象或不希望变量(在本例中为 i)在本地范围内更改时,引用才相关。

【问题讨论】:

  • 尖锐物体是什么意思?
  • 如果你先使用auto&amp; i,然后再使用i.push_back(...),你就会改变with。否则,您将更改内部 vector 的副本

标签: c++ reference stl iterator range-based-loop


【解决方案1】:

auto 默认既不是const 也不是引用。所以for (auto i : with) { 按值存储到i,它为每个嵌套的vectors 调用复制构造函数。该副本与存储在您的vectors 中的vector 中的版本无关,因此当副本消失时不会保留任何更改。您添加的 &amp; 使其成为别名底层内部 vector 的引用,因此对引用的更改会更改原始 vector

如果您不想想要更改有问题的对象,执行此操作的有效方法是使用const auto&amp; 来防止更改并避免复制;除非您真的想要一个不会影响原始副本的可变副本,否则您很少希望以这种方式按值进行迭代,因为复制构造函数的成本可能会变得非常讨厌。

【讨论】:

  • auto 默认是什么?如果我改用vector&lt;int&gt; i,同样的错误还会持续吗?
  • @bayesianpower:你会得到同样的错误; auto 已经对 vector&lt;int&gt; 进行了类型推断,但您仍需对 const 负责,或者如果需要,请对其进行引用限定。
  • 每当我在 C++ 中使用相等时,这通常是正确的吗?例如: 1. 如果我有一个函数int A(vector&lt;int&gt; B) {...,那么B 会是我传入的向量的副本吗? 2. 任何时候我迭代任何容器:被迭代的变量总是一个副本?那么在没有指针的情况下修改底层数据的唯一方法是在每种情况下都使用引用吗?
  • @bayesianpower 你真的应该从 good c++ book 开始。你所有的问题都是关于基本的 C++ 概念,比如值和引用,你应该从一个好的来源真正学习它们,而不是你在黑暗中扔飞镖希望有什么东西能坚持,然后在你去的时候试图弄清楚基本概念。
【解决方案2】:

在使用for (auto i : with) 时,您是从向量with 复制元素i 然后使用它。

在使用for (auto &amp; i : with) 时,您从向量with 中引用元素i,然后使用它。

如果您复制其元素的地址然后取消引用(或者您使用的是指针向量),您的向量将会改变,但这里您正在复制对象。

【讨论】:

    【解决方案3】:

    for (auto i : with) { ... 等价于:

    for (vector<int>::iterator it = with.begin(); it != i.end(); it++)
    {
        vector<int> i = *it;
        ...
    

    然后您可以看到i 每次循环时都会生成一个副本。因此,对此副本的更改只会影响副本,这是一个临时的。

    OTOH for (auto &amp;i : with) ... 相当于:

    for (vector<int>::iterator it = with.begin(); it != i.end(); it++)
    {
        vector<int>& i = *it;
        ...
    

    每次循环分配一个引用。因此,对此引用的更改会影响原始对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多