【问题标题】:How to pass a temporary vector by const reference?如何通过 const 引用传递临时向量?
【发布时间】:2013-06-28 11:46:47
【问题描述】:

我需要对以下代码执行什么操作才能输出AB 的值?喜欢的话可以编辑编译here

typedef const std::vector<int>& t;

class SomeClass
{
    t data;
public:
    SomeClass(t _data) : data(_data) {}
    void disp()
    {
        for (auto v : data)
            std::cout << v << ", ";
        std::cout << std::endl;
    }        
};

int A = 1;
int B = 2;

SomeClass f = SomeClass( {A, B} );
f.disp();

A = 456;
f.disp();

【问题讨论】:

  • 你确定{A, B}不是一个临时对象(向量)并且在SomeClass的构造函数退出后它没有被销毁吗?
  • 在构造函数中绑定临时变量不会延长生命周期。如果您对此不太满意,请不要使用参考成员。
  • 你有typedef const std::vector&lt;int&gt;&amp; t 你的班级成员不能是t datatype 把它改成std::vector&lt;int&gt; data

标签: c++ reference pass-by-reference


【解决方案1】:

根据您的代码,您似乎希望能够从类外部更新向量的元素。

但是,在开始之前,存在一个问题,即您正在存储对临时对象的引用(由{1, 2} 组成的vector)。当调用 SomeClass( {A, B} ) 完成时,此对象将被释放。

有三种方法可以解决这个问题:

  1. 如果您知道SomeClass 对象的生命周期,则可以将副本复制到SomeClass 实例f 之外的向量。例如,如果f 仅在创建它的函数的持续时间内存在,您可以执行类似的操作

    std::vector<int>   aVector({A, B});
    SomeClass          f = SomeClass(aVector);
    

    创建函数“拥有”aVector,并且f 对它有一个引用。

  2. 您可以让SomeClass 实例复制向量。为此,您可以通过引用传递向量,但在构造函数中进行复制:

    class SomeClass
    {
        std::vector<int>    data;
      public:
        SomeClass(const std::vector<int> &_data) : data(_data) {}
        ...
    }
    

    f 现在“拥有”它自己的向量副本。但是,您现在将无法从对象外部更改元素的值,因此您需要将指针存储在向量内 (std::vector&lt;int*&gt;) 或在类中提供用于更改内容的方法(如果这是一个选项) .

  3. 您可以使用移动语义 (C++11) 确保参数向量的内部存储不被复制,而是在构造过程中重新分配给 SomeClass::data

    class SomeClass
    {
        std::vector<int>    data;
      public:
        SomeClass(std::vector<int> &&_data) : data(std::move(_data)) {}
        ...
    }
    

    和以前一样,f“拥有”向量。同样,无法从对象外部更改 f.data 的内容,因此您需要将指针存储在向量中或提供方法。

在上述任何一种情况下,您都无法通过更新A 来更改向量的内容。这是因为在创建向量时会复制A,并且该副本将保留值1

在情况 (2) 和 (3) 中,为了能够通过更新 A 来更新向量,您必须在向量中存储指针,如前所述。您也可以在情况 (1) 中执行此操作。请注意,在存储指针时,您需要确保它们指向的内存在您可以使用指针时一直存在——本质上与使用向量本身解决的所有权问题相同。

在情况(1)中,也可以通过更新aVector[0]来更新vector的内容,因为f有对aVector的引用。

【讨论】:

    【解决方案2】:

    我会说使用指针,并在你的类中保存一个真正的向量而不是一个引用

    #include <iostream>
    #include <vector>
    
    int main()
    {
    //This is now a vector type, not a reference to vector. Also, it contains
    // pointer to int instead of a copy.
    typedef const std::vector<int *> t; 
    
    class SomeClass
    {
        t data;
    public:
    
    // We pass the vector by reference here.
    
        SomeClass(t & _data) : data(_data) {}
        void disp()
        {
            for (auto v : data)
                std::cout << *v << ", ";
            std::cout << std::endl;
        }        
    };
    
    int A = 1;
    int B = 2;
    
    // We have to pass the address of A and B here.
    SomeClass f = SomeClass( {&A, &B} );
    f.disp();
    
    A = 456;
    f.disp();
    }
    

    但是,由于我们持有 A 和 B 上的指针(它们是本地的),一旦 A 和 B 被丢弃(基本上是下一个 '}'),向量将持有指向无效值的指针,这很糟糕。

    在您的示例中,您的类与 A 和 B 一起被丢弃,所以没关系,但如果您的类比 A 和 B 存活的时间更长,则 disp() 的行为将是未定义的(可能是 SIGSEGV)。

    【讨论】:

      【解决方案3】:

      目前,您在类中持有对临时对象的引用,并且取消引用它会触发未定义的行为。您需要将 typedef 更改为 vector(remove &) 并在构造函数中添加: SomeClass(t& _data) 以便在类中保留一个实际对象并接受构造函数参数作为参考

      【讨论】:

        【解决方案4】:

        您需要一个更永久的向量才能使您的示例正常工作。

        您所说的类是可以的,但必须记录自己以存储传递的引用,因此 REQUIRE 参数具有对 SomeClass 实例的生命周期的爱。

        您当前的调用在那里失败:您传入一个临时创建的向量,并在该行的末尾被销毁。当您进入下一行时,您的 f 持有一个悬空引用,使用它会将您置于未定义的行为领域。

        在单独的行中修复 vreate 向量并将其传递给 SomeClass ctor。

        【讨论】:

          【解决方案5】:

          三个错误。

          1. 这不是初始化列表。
          2. f 没有按预期分配。
          3. 数据没有值的地址

          所以:

          #include <iostream>
          #include <string>
          #include <vector>
          
          using namespace std;
          typedef const std::vector<int*>& t;
          
          class SomeClass
          {
              t data;
          public:
              SomeClass(t& _data) : data(_data) {}
              void disp()
              {
                  for (auto v : data)
                      std::cout << *v << ", ";
                  std::cout << std::endl;
              }        
          };
          
          int
          main(int argc, char* argv[]) {
              int A = 1;
              int B = 2;
              t v = {&A, &B};
          
              SomeClass f(v);
              f.disp();
          
              A = 456;
              f.disp();
              return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-08-08
            • 1970-01-01
            • 2019-03-02
            • 2012-06-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多