我需要对以下代码执行哪些操作才能输出A
和B
的值?如果您愿意,可以编辑和编译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();
答案 0 :(得分:2)
根据您的代码,您似乎希望可以从类外部更新向量的元素。
但是,在开始之前,存在一个问题,即您正在存储对临时对象(由vector
组成的{1, 2}
)的引用。当调用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
。
答案 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)
有三个错误。
所以:
#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;
}