来自Java,我对如何正确访问存储在向量中的对象感到困惑。
在这个测试用例中,我希望两个输出显示相同的数字(2):
#include <iostream>
#include <vector>
using namespace std;
class Item {
public:
int id = 0;
Item(int id)
{
this->id = id;
}
};
int main()
{
vector<Item> items;
Item item = Item(1);
items.push_back(item);
Item itemFromVector = items.at(0);
itemFromVector.id = 2;
cout << "item: " << item.id << endl;
cout << "itemFromVector: " << itemFromVector.id << endl;
}
// output:
// item: 1
// itemFromVector: 2
答案 0 :(得分:3)
在这种情况下,您的item.id
等于1。
这背后的原因是push_back
调用将在向量中执行对象的COPY(向量中的Item
和item
是2个不同的对象)。
观察你想要达到的目的的一种方法是使用指针:
int main()
{
vector<Item*> items; //items contains addresses of Item object
Item item = Item(1);
items.push_back(&item); // push address of your item
Item* itemFromVector = items.at(0); // Pointer to item
itemFromVector->id = 2; // Modify item id attribute
cout << "item: " << item.id << endl; // Access item id attribute
cout << "itemFromVector: " << itemFromVector->id << endl; // Access item id attribute
}
答案 1 :(得分:1)
执行时:
items.push_back(item);
item
的副本存储在向量中。两个对象item
和向量中的副本是完全独立的对象。对一个的更改不会影响另一个。
如果您希望能够更改一个并希望更改反映在另一个中,则需要创建一个指针向量或std::reference_wrapper
s的向量。
#include <iostream>
#include <vector>
#include <functional>
class Item {
public:
int id = 0;
Item(int id)
{
this->id = id;
}
};
void test1()
{
std::cout << "Output from test1() ...\n";
std::vector<Item*> items;
Item item(1);
items.push_back(&item);
Item* itemFromVector = items.at(0);
itemFromVector->id = 2;
std::cout << "item: " << item.id << std::endl;
std::cout << "itemFromVector: " << itemFromVector->id << std::endl;
}
void test2()
{
std::cout << "Output from test1() ...\n";
std::vector<std::reference_wrapper<Item>> items;
Item item(1);
items.push_back(item);
Item& itemFromVector = items.at(0);
itemFromVector.id = 20;
std::cout << "item: " << item.id << std::endl;
std::cout << "itemFromVector: " << itemFromVector.id << std::endl;
}
int main()
{
test1();
test2();
}
输出:
Output from test1() ...
item: 2
itemFromVector: 2
Output from test1() ...
item: 20
itemFromVector: 20
答案 2 :(得分:1)
vector<Item> items;
在此代码中,您有一个Item类列表
当您致电items.push_back(item);
时,您会在item
数组中推送items
的副本。因此,当您致电itemFromVector.id = 2;
时,您更改了刚刚放入数组中的副本的ID。
如果您要将原始item
对象复制到数组中并在之后进行编辑,则必须执行以下更改:
vector<Item*> items;
items.push_back(&item);
Item* itemFromVector = items.at(0);
itemFromVector->id = 2;
在第一行中,您告诉向量我们要存储Item
类的指针而不是它的副本。
在第二行中,我们通过在变量名称前添加item
将&
的地址推送到数组中。
在第三行中,我们通过在变量名之前添加Item
来告诉编译器我们的变量类型是*
类的指针。
在第四行中,我们将.
更改为->
,因为我们正在使用指针对象。
答案 3 :(得分:1)
由于您来自Java,因此在C ++中使用引用并不难以获得预期的行为。
项目项目=项目(1);
与Java不同,此处的item不是引用,而是实际的实例。你可以在没有任务的情况下立即构建它:
Item item(1);
items.push_back(项目);
在这里你需要知道你在向量中推送的内容不是对项目的引用,而是它的副本,一个从项目中复制的真实新实例。
Item itemFromVector = items.at(0);
在这里,您将itemFromVector作为引用应用于向量中的第一项。但实际上它是从中复制的实例。如果你想要一个引用,请将它声明为引用,就这么简单:
Item& itemFromVector = items.at(0);
总之,在使用Java时,一切都是参考。在C ++中并非如此。仅当引用显式声明为引用时,引用才是引用。
答案 4 :(得分:1)
Item(int id) { this->id = id; }
这是典型的Java主义。特殊的C ++方式是:
Item(int id) : id(id) {}
Item item = Item(1);
这也是。特殊的C ++方式是:
Item item(1);
items.push_back(item);
这会创建item
的副本,并将副本存储在向量中。
Item itemFromVector = items.at(0);
同样,这会创建第一个项目的副本并将其存储在itemFromVector
变量中。
您可能会想到Java代码,例如:
List<Item> list = new ArrayList<Item>();
list.add(item);
Item item = list.get(0);
但这是错误的类比。 Java只是在列表中存储指针。更合适的Java类比是:
List<Item> list = new ArrayList<Item>();
list.add(item.clone());
Item item = list.get(0).clone();
如果您希望C ++展示Java list.add(item); Item item = list.get(0);
的行为,那么您必须创建一个指针向量:
vector<Item*> items;
Item item(1);
items.push_back(&item);
Item* itemFromVector = items.at(0);
itemFromVector->id = 2;
但是C ++不是Java,所以这不是常见的事情,并导致与C ++没有任何内置垃圾收集这一事实相关的各种问题。作为一般准则,如果可以,请避免使用指针,并特别注意指向本地对象的指针。