由于我不会进入的原因,我创建了一个看起来像这样的基本链表:
class Linked
{
...
std::unique_ptr<Linked> next;
std::string data;
}
我想实现一个将遍历列表的const方法,因此:
std::string Linked::getAllData() const
{
std::string allData = data;
const std::string delimiter = " : ";
for( std::unique_ptr<Linked> &i = next; i != nullptr; i = i->next )
allData += delimiter + i->data;
return allData;
}
看起来很简单。但到目前为止,我还没有超越编译器对constness的抱怨。我想我的问题稍微有点根本。我不想在迭代时修改每个元素,但我也不想要const对象。如果是这些老派的c指针,那么使用const Linked *
代替const Linked * const
就是一件简单的事情,因为指针考虑了这个想法(变量本身可能不会被重新分配)与变量相比,指向const数据)。似乎std :: unique_ptr(是一个普通的类)并没有完全分享这个概念。
唯一可以解决这个问题的方法是写一个const_iterator吗?这对我来说似乎有点难看,而且对于一个非常简单的类和非常简单的方法来说有很多不妥。简单地迭代const链表的最佳方法是什么?
答案 0 :(得分:1)
在处理常量问题之前,首先要解决其他问题。您对指针和引用如何工作的基本理解有点不合适。即使这里没有const
问题,你的for循环也至少会以两种不同的方式完全打破:
for( std::unique_ptr<Linked> &i = next; i != nullptr; i = i->next )
对于初学者,您无法比较对nullptr
的引用。忽略常量问题:i
被声明为引用,因此i != nullptr
无效,const
。只能将指针与nullptr
进行比较,而i
不是指针。它是一个参考。
然后我们开始:i=i->next;
由于i
是引用,因此 覆盖 对象i
引用新的价值。这显然不是您的意图:用next
中的任何内容来破坏您班级中的next->next
指针。
首先,您根本不需要参考资料。一个简单的指针就可以了,你在这里显然需要做的唯一事情是使用一个普通的,花园式的指针:
for( Linked *i = next.get(); i != nullptr; i = i->next.get() )
这完全将const
问题从雷达屏幕上移开。它根本不再是一个因素。
此外,我还强烈怀疑您打算使用this
开始迭代,可能是:
for( Linked *i = this; i != nullptr; i = i->next.get() )
答案 1 :(得分:1)
您不应在遍历功能中使用unique_ptr
。 unique_ptr
表示对象的引用和该对象的关联所有权的概念。这对于遍历方法来说是不正确的,遍历方法应该只涉及对象的引用,而所有权保留在Linked列表本身(而不是转移到getAllData
函数中的局部变量中)。
只需使用Linked const*
从unique_ptr
获取unique_ptr::get()
,然后从那里继续:
std::string Linked::getAllData() const
{
std::string allData = data; //Initialise 'allData' with 'data' and
//eliminate the unused 'message' variable.
//(I'm guessing this was just a typo in
// your question)
const std::string delimiter = " : ";
//Use 'Linked*' rather than 'unique_ptr', since there is should be no
//ownership management involved in traversing the list.
for (Linked const *i = next.get(); i != nullptr; i = i->next.get()) {
allData += delimiter + i->data;
}
return allData;
}
答案 2 :(得分:0)
对T的引用可以使用类型为T的对象,类型为T的函数或可隐式转换为T的对象进行初始化。一旦初始化,就无法更改引用以引用另一个对象。
意识到这一点,我想到了另一个想法,它允许我绑定一个引用(不转移所有权,因为引用不会这样做),维护const正确性,并防止使用旧式原始指针。但它涉及尾递归。我想这是一种不会过早优化的情况?
void appendDataRecursively(std::string &data, const std::unique_ptr<Linked> &node)
{
static const std::string delimiter = " : ";
if(node == nullptr) return;//yes, I can compare it to nullptr
data += delimiter + node->data;
appendDataRecursively(data, node->next);
}
std::string Linked::getAllData() const
{
std::string allData = data;//make a local copy so the copy can be modified
appendDataRecursively(data, next);//append each element in the list
return allData;//Tada!
}