是否可以从 const 方法迭代链表
Is it possible to iterate over a linked list from a const method
出于我不想讨论的原因,我创建了一个基本的链表,看起来像这样:
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;
}
似乎很简单。但到目前为止,我还没有摆脱编译器对恒常性的抱怨。我想我的问题稍微基本一些。我不想在迭代时修改每个元素,但我也不想使用 const 对象。如果这些老式的c指针,那么使用const Linked *
而不是const Linked * const
将是一个简单的问题,因为指针是考虑到这个想法的(是它们本身可能不会被重新分配的变量,而不是变量,点到常量数据)。似乎 std::unique_ptr(作为一个普通类)并不完全认同这个概念。
解决这个问题的唯一方法真的是写我的一个const_iterator吗?这对我来说似乎有点丑陋,对于一个非常简单的类和非常简单的方法来说,这很麻烦。简单地迭代常量链表的最佳方法是什么?
不应在遍历函数中使用unique_ptr
。unique_ptr
表示对对象的引用的概念以及该对象的关联所有权。这对于遍历方法来说是不正确的,遍历方法应该只涉及对对象的引用,而所有权保留在链表本身(而不是转移到getAllData
函数中的局部变量中)。
只需从带有unique_ptr::get()
的unique_ptr
获取Linked const*
,然后从那里继续:
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;
}
在处理恒常性问题之前,您还有其他问题需要先解决。您对指针和引用如何工作的基本理解有些偏离目标。即使这里没有const
问题,您的 for 循环至少以两种不同的方式完全中断:
for( std::unique_ptr<Linked> &i = next; i != nullptr; i = i->next )
对于初学者,您无法将引用与nullptr
进行比较。忽略恒定性问题:i
被声明为引用,因此无论是否const
i != nullptr
都不起作用。只有指针可以比作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() )
呃,这是一个丑陋的答案。需要明确的是,我不想使用原始指针进行迭代的全部原因与我一开始不想使用原始指针的原因相同:它们乞求内存泄漏等。通过阅读有关引用的信息,我确实得到了一些灵感,这些引用不能被反弹(指针可以)http://en.cppreference.com/w/cpp/language/reference_initialization
对 T 的引用可以使用 T 类型的对象、T 类型的函数或可隐式转换为 T 的对象进行初始化。初始化后,无法更改引用以引用另一个对象。
意识到这一点,我想到了另一个想法,它允许我绑定引用(无需转移所有权,因为引用是习惯的),保持常量正确性,并防止使用旧式原始指针。但它涉及尾递归。我想这是一种不过早优化的情况?
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!
}
- 在C++中迭代 2D 容器的最干净方法
- C++11 迭代向量的新方法?
- 在C++上实现高斯赛德尔迭代方法
- 使用迭代器替换映射中的常量项的方法
- C++:std::ofstream 方法 open() 在第二次迭代时擦除打开的 ifstream 文件
- 在unordered_multimap中精确迭代一次每个键的有效方法
- 向后迭代 std::array 或 std::vector 的正确方法是什么?
- 创建可以遍历 std::map 值的通用模板迭代器的最简单方法是什么?
- 从基于迭代器的for循环转换后,如何在map::find()中调用方法
- 在 C++17 中实现迭代器和const_iterator的正确方法是什么?
- 如何在不迭代的情况下对数组中的每个元素调用方法
- 编译错误 std::vector<std::shared_ptr<T>>迭代器和擦除方法
- 在 c++ 中迭代对列表的正确方法?
- 如何使用 SFINAE 从 end() 方法返回 (const_) 迭代器
- 如何使用迭代器作为参数方法?
- 迭代快速排序方法的分区算法问题
- 迭代器方法无法从Const_iterator继承
- 我通过迭代加法将二进制数转换为十进制并检查单个字符(请参阅代码)的方法有什么问题?
- 是否可以从 const 方法迭代链表
- 龙格-库塔四阶方法迭代时的累积误差