【问题标题】:copying std list with pointers to another std list with pointers将带有指针的 std 列表复制到带有指针的另一个 std 列表
【发布时间】:2017-04-15 05:12:31
【问题描述】:

我正在尝试将指针列表的值复制到另一个指针列表中。当我删除第一个指针的分配时,值不会保留在第二个列表中。我知道这特别是因为它是一个指针列表,并且地址被复制而不是实际值。我想知道我将如何去做这件事。

以下是我的代码:

#include <iostream>
#include <list>


int main(int argc, char const *argv[])
{
  std::list<int*> pointer_list;

  std::list<int*> int_list;


  int one, two, three, four, five;

  one = 1;
  two = 2;
  three = 3;
  four = 4;
  five = 5;

  pointer_list.push_back(new int(one));
  pointer_list.push_back(new int(two));
  pointer_list.push_back(new int(three));
  pointer_list.push_back(new int(four));
  pointer_list.push_back(new int(five));



  for (std::list<int*>::iterator iterator = pointer_list.begin(), end = pointer_list.end(); iterator != end; ++iterator)
  {
    std::cout << **iterator << std::endl;
  }

  for (std::list<int*>::iterator iterator = pointer_list.begin(), end = pointer_list.end(); iterator != end; ++iterator)
  {
    int_list.push_back(*iterator);
  }

  for (std::list<int*>::iterator iterator = pointer_list.begin(), end = pointer_list.end(); iterator != end; ++iterator)
  {
    delete *iterator;
  }

  for (std::list<int*>::iterator iterator = int_list.begin(), end = int_list.end(); iterator != end; ++iterator)
  {
    std::cout << "INT_LIST_AFTER DELETE: " << **iterator << std::endl;
  }

  for (std::list<int*>::iterator iterator = pointer_list.begin(), end = pointer_list.end(); iterator != end; ++iterator)
  {
    std::cout << "LIST_POINTER AFTER DELETE: " << **iterator << std::endl;
  }


  return 0;
}

以下是输出:

  1
  2
  3
  4
  5
  INT_LIST_AFTER DELETE: 1469317922
  INT_LIST_AFTER DELETE: 1469317925
  INT_LIST_AFTER DELETE: 1469317928
  INT_LIST_AFTER DELETE: 0
  INT_LIST_AFTER DELETE: 5
  LIST_POINTER AFTER DELETE: 1469317922
  LIST_POINTER AFTER DELETE: 1469317925
  LIST_POINTER AFTER DELETE: 1469317928
  LIST_POINTER AFTER DELETE: 0
  LIST_POINTER AFTER DELETE: 5

另外,我将如何删除最后一个元素?当我遍历列表时,条件 iterator != end 会阻止它,并且由于列表的性质,我不能使用 &lt;=

【问题讨论】:

  • 为什么要存储指针?如果您只是在处理ints,请使用它们并删除指针。
  • “我想知道我将如何去做这件事” - 如何去做 what ?您已经确定了问题所在。你有一个充满悬空指针的列表。所以..要么不使用指针,要么使用可以在列表之间共享的东西,比如std::shared_ptr&lt;int&gt;而不是int*
  • 如果可能,我正在尝试实现一个指向另一个指针列表的深层副本。
  • 所以根本不要使用指针。使用std::list&lt;int&gt;
  • @a-one,你得到一个深拷贝,因为人们通常会解释这一点,因为你将列表解释为列表 指针。指针值被复制。如果您希望第二个列表包含与第一个列表不同的指针,那么您需要为它们分配空间以指向并适当地初始化该空间。

标签: c++ pointers memory-management stl


【解决方案1】:

我经常在 std::list 或 std::vector 中使用指针来避免复制,从而提高速度。 当然,该示例使用 int 指针,这仅用于示例。

std::vector<int> list_int;
std::vector<int> list_int_copy;

std::vector<std::unique_ptr< int >> list_heap_unique;
std::vector<std::unique_ptr< int >> list_heap_unique_copy;


for(int i=0;i<5;i++) {
        list_int.push_back(i);
        //std::unique_ptr<int> ptr(new int(i));
        list_heap_unique.emplace_back(new int(i));// new int(i)); // allocate object to heap memory
        std::cout << i << ": orig i:" <<  list_int.at(i) << ", heap " << *list_heap_unique.at(i) << " ptr 0x" << (void *)list_heap_unique.at(i).get(); // << std::endl;
}

std::copy(list_int.begin(),list_int.end(), std::back_inserter(list_int_copy));

for (int val: list_int_copy) {
       std::cout << "copy val int: "  << val; // << std::endl;
}

std::copy(std::make_move_iterator(list_heap_unique.begin()),
          std::make_move_iterator(list_heap_unique.end()),
          std::back_inserter(list_heap_unique_copy));


std::vector<std::unique_ptr<int>>::iterator iter;
for (iter = list_heap_unique_copy.begin();
     iter!= list_heap_unique_copy.end();
     ++iter)
{
     int *ptr = (*iter).get();
     if (ptr)
        std::cout << "copy val u_ptr: " << *ptr;// << std::endl;
}

使用普通指针,在使用后删除容器的内容并不难。 这取决于您在列表中添加或删除元素的方式和位置。

【讨论】:

    【解决方案2】:

    std::vectorstd::list 等STL 容器中存储原始 拥有 指针是错误和“泄漏” 的来源(例如如果抛出异常,分配的资源就会泄露,因为 STL 容器的析构函数不会释放原始拥有的指针)。
    您应该存储,或者使用智能指针(观察原始指针很好,如果你注意它们的生命周期)。

    如果您真的想在 STL 容器中存储指针,并且想要 共享所有权 语义,您可能需要考虑 std::shared_ptr。例如。你可以有std::list&lt;std::shared_ptr&lt;T&gt;&gt;(在你的情况下是list&lt;shared_ptr&lt;int&gt;&gt;)。

    在这种情况下,您可以执行复制操作,这将转化为 引用计数 操作(例如,当复制某些内容时,而不是深度复制,您会获得增加的引用计数;这一切都是自动的由std::shared_ptr管理)。

    【讨论】:

    • 感谢您的帮助,非常感谢并且没有被忽视,我的问题的答案是:int temp = **iterator; int_list.push_back(new int(temp));
    • 是的,但是如果要将原始指针存储在 STL 容器中,那么 OP 想要执行的复制类型正是 应该 执行的那种,如它不会创建任何(额外的)别名。
    • 感谢您抽出宝贵的时间@John Bollinger
    • @a-one: int_list.push_back(new int(temp)) not 如果 int_list 是一个 std::list 存储原始 owning 指针,则 int_list.push_back(new int(temp)) 不是好的 IMO。如果您想要唯一的所有权,请考虑使用std::unique_ptr 而不是shared_ptr
    猜你喜欢
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多