尽管我有很多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()
创建给它的参数的副本(我忽略了移动语义-在这里不使用它们)。注意什么是自变量-之前引用过的masterItem
或m1
被取消引用。由
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个对象:
m1
,m2
,s1
和s2
(均为ItemToBeFound
类型)堆栈上有2个对象:
masterItem
和slaveItem
(均为指针类型)全局区域中的一个对象:
myList
(在此处可以视为堆栈对象)m2
和s2
存储在myList
中,并且可以在s1
和s2
都有指向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/