[英]How to pass a temporary vector by const reference?
我需要对以下代码进行什么操作才能使其输出A
和B
的值? 您可以根据需要在此处进行编辑和编译。
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} )
将释放此对象。
有三种解决方法:
如果知道SomeClass
对象的生存期,则可以在SomeClass
实例f
外部将副本复制到向量。 例如,如果f
仅在创建它的函数期间存在,则可以执行以下操作
std::vector<int> aVector({A, B}); SomeClass f = SomeClass(aVector);
创建函数“拥有” aVector
,并且f
具有对其的引用。
您可以让SomeClass
实例复制该向量。 为此,您可以按引用传递矢量,但是在构造函数中创建一个副本:
class SomeClass { std::vector<int> data; public: SomeClass(const std::vector<int> &_data) : data(_data) {} ... }
f
现在“拥有”它自己的向量副本。 但是,您现在将无法从对象外部更改元素的值,因此您将希望将指针存储在向量( std::vector<int*>
)内,或在类中提供一种用于更改内容的方法,如果可以的话。
您可以使用移动语义(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。
有三个错误。
所以:
#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.