如何通过const引用传递临时向量?

时间:2013-06-28 11:46:48

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

我需要对以下代码执行哪些操作才能输出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();

5 个答案:

答案 0 :(得分:2)

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

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

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

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

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

    创建功能“拥有”aVectorf引用了它。

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

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

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

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

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

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

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

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

    如果是(1),您还可以通过更新aVector[0]来更新向量的内容,因为f引用了aVector

答案 1 :(得分:1)

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

#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)。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您的示例需要一个更永久的向量。

你提出的类是可以的,但是必须将自己记录到 store 传递的引用,所以REQUIRE参数有着对SomeClass实例的热爱。

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

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

答案 4 :(得分:0)

有三个错误。

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

    #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;
    }