使用存储在向量中的对象的正确方法是什么?

时间:2015-11-08 18:39:40

标签: c++ vector reference

来自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

5 个答案:

答案 0 :(得分:3)

在这种情况下,您的item.id等于1。

这背后的原因是push_back调用将在向量中执行对象的COPY(向量中的Itemitem是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 ++没有任何内置垃圾收集这一事实相关的各种问题。作为一般准则,如果可以,请避免使用指针,并特别注意指向本地对象的指针。