尽管我有很多C嵌入式程序员的经验,但实际上我对C ++并不熟练。我正在实现一个解析器,其中ItemsToBeFound被推入列表中。

碰巧这些项目中的某些(例如“主项目”)具有更多信息,因此其他一些项目(“从属项目”)需要引用“主项目”来检索这些信息。此链接是在总体阶段完成的,没有迭代器。

所以:


我将指针保存到主项目,然后将其推到列表中
我将指向主项目的指针保存在从属项目的特定字段中
后来,我开始遍历列表
我将解析的信息保存到主项目
当涉及到处理从属项目时,我尝试访问主项目的字段。但这并没有改变!
迭代过程中指向主项目的指针与原始指针不同,因此从属项目中包含的指针指向原始(未更改)数据


关于我可以使用某些特殊限定词来强制迭代原始数据的任何建议?我发布列表和/或迭代器的方式中是否存在明显的错误?

请注意,我可以确定上面步骤6中声明的内容,因为我已经使用调试器观看了指针值。

这是显示所描述问题的简化代码:


class ItemToBeFound
{
private:
public:
  ...
  int specialDataToBeRetreived;
  ItemToBeFound *referenceItem;
  ...
}

std::list<ItemToBeFound> myList;

void PopulateList( void )
{
  ItemToBeFound *masterItem = new ItemToBeFound( NULL /* no refItem */ );
  myList.push_back( *masterItem );

  ItemToBeFound *slaveItem = new ItemToBeFound( masterItem );
  myList.push_back( *slaveItem );
}

void mainFunction( void )
{
  // ...
  PopulateList();
  // ...

  /* Let's iterate and do something */
  std::list<ItemToBeFound>::iterator it = myList.begin();
  while( it != itemsList.end() )
  {
    if( is_a_master_item )
    {
      it->specialDataToBeRetreived = getFromFileToBeParsed();
    }
    else /* it is a slave item */
    {
      it->specialDataToBeRetreived = it->referenceItem->specialDataToBeRetreived;

      /* But it doesn't work! */
    }

    it++;
  }

  // ...
}


在迭代过程中的其他“从属”条件下,我希望在参考对象中设置“ specialDataToBeRetreived”,但我始终获得0。

我得到0的原因是,如调试器所示,迭代阶段中的引用项与原始项有不同的地址,而从属项则指向该地址。

最佳答案

迭代器不复制任何内容。用C术语来说,它们的行为几乎类似于数组中的指针。

但是,您可以在此处复制元素:

void PopulateList( void )
{
  ItemToBeFound *masterItem = new ItemToBeFound( NULL /* no refItem */ );
  myList.push_back( *masterItem ); //copy of masterItem pointee

  ItemToBeFound *slaveItem = new ItemToBeFound( masterItem ); //initialized with masterItem, which does not point to the object stored in the list!
  myList.push_back( *slaveItem ); //copy of slaveItem pointee, also stores masterItem, but not object from the list

//slaveItem is leaked here, masterItem is only kept via slaveItem copy in the list
}


如果这样初始化对象,则从属对象将永远不会存储指向列表中对象的指针,而是指向使用new创建的对象的指针。



让我们逐步看一下代码(在这里我将成为橡胶调试器):

ItemToBeFound *masterItem = new ItemToBeFound( NULL /* no refItem */ );


您在堆上分配了一个对象(它们没有名称,但我们称其为m1),并在堆栈上分配了一个名为masterItem的指针,因此取消引用的masterItem正是m1

  myList.push_back( *masterItem );


std::list::push_back()创建给它的参数的副本(我忽略了移动语义-在这里不使用它们)。注意什么是自变量-之前引用过的masterItemm1被取消引用。
m1创建的对象push_back的副本将称为m2

所以现在我们有了以下内容(a->b的意思是a指向b):

masterItem->m1
myList->m2


下一行:

  ItemToBeFound *slaveItem = new ItemToBeFound( masterItem );


在这里,使用堆上的新对象-slaveItem初始化s1

masterItem->m1
myList->m2
slaveItem->s1->masterItem->m1 (s1 points to masterItem, which points to m1)


最后一个:

myList.push_back( *slaveItem );


同样,push_back()在堆上创建其参数的副本(此副本称为s2

masterItem->m1
slaveItem->s1->masterItem->m1
myList->m2
myList->s2->masterItem->m1


最终,您将拥有:


堆上有4个对象:m1m2s1s2(均为ItemToBeFound类型)
堆栈上有2个对象:masterItemslaveItem(均为指针类型)
全局区域中的一个对象:myList(在此处可以视为堆栈对象)
m2s2存储在myList中,并且可以在
s1s2都有指向m1的指针
没有从属对象指向m2


稍后,当您运行mainFunction()时,对象m2充满了数据,但是对象s2试图从m1检索数据,而其中没有任何有价值的数据。



没有更多信息,很难提出任何解决方案。如果无法重组类结构,我将使用std::list<std::shared_ptr<ItemToBeFound>>代替,这将确保您的指针安全,并且仅将std::weak_ptr<ItemToBeFound> referenceItem存储在从属对象中(以避免任何循环依赖并明确声明所有权)。

您可能拥有std::list<ItemToBeFound*>并手动管理内存,但是这与现代C ++精神背道而驰,应格外小心-与C语言相比,C ++中的流程可以占用更多分支,并且很难将所有分支都跟踪到delete所有内容。

从技术上讲,您可以在从属对象中存储指向列表中存储的对象的指针(甚至指向这些对象的迭代器),但这听起来像一个怪异的解决方案。您不控制那些对象,也不拥有它们,因此不应保留指向这些对象的指针。

关于c++ - 通过C++中的迭代器修改列表项(副标题:是回推还是迭代器创建原始数据的拷贝?),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58103649/

10-14 18:51
查看更多