繁体   English   中英

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

[英]How to pass a temporary vector by const reference?

我需要对以下代码进行什么操作才能使其输出AB的值? 您可以根据需要在此处进行编辑和编译。

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();

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

但是,在进行此操作之前,存在一个问题,您正在存储对临时对象(由{1, 2}构成的vector的引用。 调用SomeClass( {A, B} )完成后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<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的内容,因此您将希望将指针存储在向量中或提供一个方法。

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

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

在情况(1)中,您还可以通过更新aVector[0]来更新矢量的内容,因为f引用了aVector

我会说使用指针,并在您的课程中持有一个真实的向量而不是引用

#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被丢弃(基本上是下一个'}'),向量将保存指向无效值的指针,这就是BAD。

在您的示例中,您的类被A和B丢弃,所以可以,但是,如果您的类存活的时间比A和B长,则disp()的行为将不确定(可能是SIGSEGV)。

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

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

就像您说的那样,该类还可以,但是必须自己记录以存储传递的引用,因此REQUIRE参数具有对SomeClass实例的热爱。

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

要将向量固定在单独的行中,然后将其传递给SomeClass ctor。

有三个错误。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM