C++ 如何删除两个不同 std::lists 中引用同一元素的指针?
C++ How can I remove pointers refering to the same element in two different std::lists?
我是 C++ 编程新手,所以如果我的源代码不是很出色,请不要生我的气。
为了我的研究,我必须编写一个程序来处理图中的节点和边。
我的源代码中有 2 个 std::lists
。第一个用于存储一般 Nodes
,另一个用于保存我称为 ArticleNodes
的 class 节点类型。一般来说,所有的元素都是指向创建对象的指针。
为了确定一个对象在另一个列表中是否相同,我保存了内存地址并将其与第二个列表中的元素进行比较。如果匹配,第二个元素将被删除。
现在我想删除两个列表中的一个元素:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
ArticleNode* pCurrentArticleNode;
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
for (list<ArticleNode*>::iterator itArticle = m_articlenode.begin(); itArticle != m_articlenode.end(); itArticle++)
{
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode) { m_articlenode.remove(pCurrentArticleNode); }
}
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
delete pCurrentArticleNode;
}
我可以编译它,但是当我调用该函数时,我的程序只是以 return 1 退出。
实际上,我发现 if 子句中的 remove-command 是问题所在。为什么那不起作用??
您必须使用 std::list
的 erase
方法才能在遍历列表时从列表中删除元素。
这应该可以解决问题:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
ArticleNode* pCurrentArticleNode;
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
list<ArticleNode*>::iterator itArticle = m_articlenode.begin();
while(itArticle != m_articlenode.end()) {
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode) {
m_articlenode.erase(itArticle++);
} else {
itArticle++;
}
}
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
delete pCurrentArticleNode;
}
您的代码中的一个简单问题是,如果您进入 if 条件得到满足并且它的主体被执行,您应该退出循环。 std::remove 使迭代器无效,您将在下一次迭代中遇到问题,所以这样做:
for (list<ArticleNode*>::iterator itArticle = m_articlenode.begin(); itArticle != m_articlenode.end(); itArticle++)
{
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode)
{
m_articlenode.remove(pCurrentArticleNode);
break;
}
}
总的来说,代码中还有其他问题。作为第一步,我建议使用 shared_ptr 来管理您的节点,并使用 shared_ptr 列表而不是指针列表。
当您使用 remove( )
方法从 std::list
对象中删除一个元素时,所有指向该元素的迭代器都会失效。在您的例子中,从列表 m_articlenode
中删除一个元素后,迭代器对象 itArticle
变得无效。当你增加那个迭代器时,你会得到一个未定义的行为。
注意 remove( )
方法会删除列表中具有给定值的所有项目。所以你根本不需要 for 循环。这是您函数的固定版本:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
m_articlenode.remove(pCurrentNode);
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
}
你应该更多地使用算法而不是手动完成所有事情:
void Graph::deleteNode(unsigned int nodeNumber)
{
assert (nodeNumber < m_nodes.size());
auto it = std::next( m_nodes.begin(), nodeNumber - 1 );
auto itArticle = std::find( m_articlenode.begin(), m_articlenode.end(), *it );
if( itArticle != m_articlenode.end() )
m_articlenode.erase( itArticle );
delete *it;
m_nodes.erase(it);
}
顺便说一句,您的代码删除了同一个对象两次。
I am new in programming c++, so please don't be angry with me if my
source code is not exactly brilliant.
我们都从某个地方开始。
Now I'd like to delete one element in both lists:
好的。快速提问。如果文章节点已经被删除(通过基本节点),为什么要删除它?我假设现在节点在列表中没有重复:
我的解决方案如下...我已将列表作为参数传递。查看评论:
#include <list>
#include <algorithm>
struct Node
{
virtual ~Node(){} //For dyna cast to work...
};
struct ArticleNode : Node
{
};
void deleteNode(std::list<ArticleNode*>& articleList, std::list<Node*>& m_nodes, unsigned int nodeNumber)
{
using namespace std;
if (m_nodes.size() > nodeNumber)
{
auto it = m_nodes.begin();
// Advance advances our iterator by N. No need for your for loop - less risk...
std::advance(it,nodeNumber);
Node* currentNode = *it;
//Casting is bad here, but hey, lets assume if type is wrong, we only erase
// it from Node...(Your call)?
ArticleNode* currentArticleNode = dynamic_cast<ArticleNode*>(currentNode);
if (currentArticleNode)
{
//Use find here.... KISS
auto foundPos = std::find(articleList.begin(), articleList.end(), currentArticleNode);
if (foundPos != articleList.end())
{
//No need to delete currentArticleNode, as we're deleting it already...
articleList.erase(foundPos);
}
//Assuming only one item for now...
}
//Else our node was obviously not the right type, and cannot exist in articleNodes...
m_nodes.erase(it);
delete currentNode;
}
else
{
std::cout << "No such node: " << nodeNumber << std::endl;
}
}
我是 C++ 编程新手,所以如果我的源代码不是很出色,请不要生我的气。
为了我的研究,我必须编写一个程序来处理图中的节点和边。
我的源代码中有 2 个 std::lists
。第一个用于存储一般 Nodes
,另一个用于保存我称为 ArticleNodes
的 class 节点类型。一般来说,所有的元素都是指向创建对象的指针。
为了确定一个对象在另一个列表中是否相同,我保存了内存地址并将其与第二个列表中的元素进行比较。如果匹配,第二个元素将被删除。
现在我想删除两个列表中的一个元素:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
ArticleNode* pCurrentArticleNode;
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
for (list<ArticleNode*>::iterator itArticle = m_articlenode.begin(); itArticle != m_articlenode.end(); itArticle++)
{
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode) { m_articlenode.remove(pCurrentArticleNode); }
}
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
delete pCurrentArticleNode;
}
我可以编译它,但是当我调用该函数时,我的程序只是以 return 1 退出。 实际上,我发现 if 子句中的 remove-command 是问题所在。为什么那不起作用??
您必须使用 std::list
的 erase
方法才能在遍历列表时从列表中删除元素。
这应该可以解决问题:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
ArticleNode* pCurrentArticleNode;
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
list<ArticleNode*>::iterator itArticle = m_articlenode.begin();
while(itArticle != m_articlenode.end()) {
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode) {
m_articlenode.erase(itArticle++);
} else {
itArticle++;
}
}
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
delete pCurrentArticleNode;
}
您的代码中的一个简单问题是,如果您进入 if 条件得到满足并且它的主体被执行,您应该退出循环。 std::remove 使迭代器无效,您将在下一次迭代中遇到问题,所以这样做:
for (list<ArticleNode*>::iterator itArticle = m_articlenode.begin(); itArticle != m_articlenode.end(); itArticle++)
{
pCurrentArticleNode = (*itArticle);
if(pCurrentNode==pCurrentArticleNode)
{
m_articlenode.remove(pCurrentArticleNode);
break;
}
}
总的来说,代码中还有其他问题。作为第一步,我建议使用 shared_ptr 来管理您的节点,并使用 shared_ptr 列表而不是指针列表。
当您使用 remove( )
方法从 std::list
对象中删除一个元素时,所有指向该元素的迭代器都会失效。在您的例子中,从列表 m_articlenode
中删除一个元素后,迭代器对象 itArticle
变得无效。当你增加那个迭代器时,你会得到一个未定义的行为。
注意 remove( )
方法会删除列表中具有给定值的所有项目。所以你根本不需要 for 循环。这是您函数的固定版本:
void Graph::deleteNode(unsigned int nodeNumber)
{
list<Node*>::iterator it = m_nodes.begin();
for(unsigned int i=1; i<nodeNumber; i++) { it++; }
Node* pCurrentNode = (*it);
m_articlenode.remove(pCurrentNode);
m_nodes.remove(pCurrentNode);
delete pCurrentNode;
}
你应该更多地使用算法而不是手动完成所有事情:
void Graph::deleteNode(unsigned int nodeNumber)
{
assert (nodeNumber < m_nodes.size());
auto it = std::next( m_nodes.begin(), nodeNumber - 1 );
auto itArticle = std::find( m_articlenode.begin(), m_articlenode.end(), *it );
if( itArticle != m_articlenode.end() )
m_articlenode.erase( itArticle );
delete *it;
m_nodes.erase(it);
}
顺便说一句,您的代码删除了同一个对象两次。
I am new in programming c++, so please don't be angry with me if my source code is not exactly brilliant.
我们都从某个地方开始。
Now I'd like to delete one element in both lists:
好的。快速提问。如果文章节点已经被删除(通过基本节点),为什么要删除它?我假设现在节点在列表中没有重复:
我的解决方案如下...我已将列表作为参数传递。查看评论:
#include <list>
#include <algorithm>
struct Node
{
virtual ~Node(){} //For dyna cast to work...
};
struct ArticleNode : Node
{
};
void deleteNode(std::list<ArticleNode*>& articleList, std::list<Node*>& m_nodes, unsigned int nodeNumber)
{
using namespace std;
if (m_nodes.size() > nodeNumber)
{
auto it = m_nodes.begin();
// Advance advances our iterator by N. No need for your for loop - less risk...
std::advance(it,nodeNumber);
Node* currentNode = *it;
//Casting is bad here, but hey, lets assume if type is wrong, we only erase
// it from Node...(Your call)?
ArticleNode* currentArticleNode = dynamic_cast<ArticleNode*>(currentNode);
if (currentArticleNode)
{
//Use find here.... KISS
auto foundPos = std::find(articleList.begin(), articleList.end(), currentArticleNode);
if (foundPos != articleList.end())
{
//No need to delete currentArticleNode, as we're deleting it already...
articleList.erase(foundPos);
}
//Assuming only one item for now...
}
//Else our node was obviously not the right type, and cannot exist in articleNodes...
m_nodes.erase(it);
delete currentNode;
}
else
{
std::cout << "No such node: " << nodeNumber << std::endl;
}
}