为什么我可以更新 const 成员函数中的成员变量?
Why can I update member variables in a const member function?
我正在尝试实现一个链表,类似于它在 STL 中的实现方式。在实现迭代器时,我创建了一些 const 成员函数(因此用户可以使用 const 迭代器)并注意到我能够更新成员变量而不会出现编译器错误。该代码使用模板,但我测试了它调用一个使用 begin() 和 const 列表的函数,所以我知道修改成员变量的模板函数是由编译器生成的。有谁知道为什么会这样?有问题的函数是 operator++ 的 const 版本。
这是我的程序的一个版本,删除了不相关的细节。
template<typename E>
struct Link {
E val {};
Link* next = nullptr;
Link* prev = nullptr;
};
template<typename E>
struct List {
struct Iterator {
Iterator(Link<E>* c) : curr{c} { }
Iterator& operator++();
const Iterator& operator++() const;
const E& operator*() const {return curr->val;}
E& operator*() {return curr->val;}
// ...
private:
Link<E>* curr;
};
// Constructors, etc ...
// Operations ...
E& front() {return head->val;}
const E& front() const {return head->val;}
Iterator begin() {return Iterator{head};}
const Iterator begin() const {return Iterator{head};}
// Other iterator stuff ...
private:
Link<E>* head;
Link<E>* tail;
int sz;
};
/*---------------------------------------------*/
template<typename E>
typename List<E>::Iterator& List<E>::Iterator::operator++() {
curr = curr->next;
return *this;
}
template<typename E>
const typename List<E>::Iterator&
List<E>::Iterator::operator++() const
{
curr = curr->next;
return *this;
}
我认为从概念上讲,制作一个 const 版本的 operator++ 是有意义的,即使它修改了成员变量。 const 迭代器实际上指的是 Link 指针的内容是 const,这正是它在解引用运算符中 returns a const E& 的原因。因此,使用 const 迭代器,您永远无法更新迭代器的内容。
让我知道是否有任何我应该包含在代码片段中的内容,谢谢!
模板函数在实例化之前实际上不会检查错误。如果你不打电话给他们,他们就会坐在那里不被注意,就像炸弹等着爆炸一样。添加对 Iterator::operator++() const
.
的调用后,您将收到编译器错误
比如我加了:
int main() {
List<int> list;
const List<int>::Iterator iter = list.begin();
++iter;
}
现在 clang 抱怨:
main.cpp:52:10: error: cannot assign to non-static data member within const
member function 'operator++'
curr = curr->next;
~~~~ ^
main.cpp:61:3: note: in instantiation of member function
'List<int>::Iterator::operator++' requested here
++iter;
^
main.cpp:14:25: note: member function 'List<int>::Iterator::operator++' is
declared const here
const Iterator& operator++() const;
^
(Repl)
I think conceptually, it makes sense to make a const version of operator++ even though it modifies member variables. A const iterator actually refers to the contents of the Link pointer being const, which is exactly why it returns a const E& in the dereference operator. Thus, with a const iterator, you can never update the contents of the iterator.
A const
迭代器不应该是可变的,也不应该有 ++
运算符。 STL 实际上有不同的 iterator
和 const_iterator
类型。 const_iterator
体现了您所描述的概念:迭代器本身是可变的,但它指向的是 const
.
我建议您效仿并创建一个单独的 ConstIterator
class.
我正在尝试实现一个链表,类似于它在 STL 中的实现方式。在实现迭代器时,我创建了一些 const 成员函数(因此用户可以使用 const 迭代器)并注意到我能够更新成员变量而不会出现编译器错误。该代码使用模板,但我测试了它调用一个使用 begin() 和 const 列表的函数,所以我知道修改成员变量的模板函数是由编译器生成的。有谁知道为什么会这样?有问题的函数是 operator++ 的 const 版本。
这是我的程序的一个版本,删除了不相关的细节。
template<typename E>
struct Link {
E val {};
Link* next = nullptr;
Link* prev = nullptr;
};
template<typename E>
struct List {
struct Iterator {
Iterator(Link<E>* c) : curr{c} { }
Iterator& operator++();
const Iterator& operator++() const;
const E& operator*() const {return curr->val;}
E& operator*() {return curr->val;}
// ...
private:
Link<E>* curr;
};
// Constructors, etc ...
// Operations ...
E& front() {return head->val;}
const E& front() const {return head->val;}
Iterator begin() {return Iterator{head};}
const Iterator begin() const {return Iterator{head};}
// Other iterator stuff ...
private:
Link<E>* head;
Link<E>* tail;
int sz;
};
/*---------------------------------------------*/
template<typename E>
typename List<E>::Iterator& List<E>::Iterator::operator++() {
curr = curr->next;
return *this;
}
template<typename E>
const typename List<E>::Iterator&
List<E>::Iterator::operator++() const
{
curr = curr->next;
return *this;
}
我认为从概念上讲,制作一个 const 版本的 operator++ 是有意义的,即使它修改了成员变量。 const 迭代器实际上指的是 Link 指针的内容是 const,这正是它在解引用运算符中 returns a const E& 的原因。因此,使用 const 迭代器,您永远无法更新迭代器的内容。
让我知道是否有任何我应该包含在代码片段中的内容,谢谢!
模板函数在实例化之前实际上不会检查错误。如果你不打电话给他们,他们就会坐在那里不被注意,就像炸弹等着爆炸一样。添加对 Iterator::operator++() const
.
比如我加了:
int main() {
List<int> list;
const List<int>::Iterator iter = list.begin();
++iter;
}
现在 clang 抱怨:
main.cpp:52:10: error: cannot assign to non-static data member within const
member function 'operator++'
curr = curr->next;
~~~~ ^
main.cpp:61:3: note: in instantiation of member function
'List<int>::Iterator::operator++' requested here
++iter;
^
main.cpp:14:25: note: member function 'List<int>::Iterator::operator++' is
declared const here
const Iterator& operator++() const;
^
(Repl)
I think conceptually, it makes sense to make a const version of operator++ even though it modifies member variables. A const iterator actually refers to the contents of the Link pointer being const, which is exactly why it returns a const E& in the dereference operator. Thus, with a const iterator, you can never update the contents of the iterator.
A const
迭代器不应该是可变的,也不应该有 ++
运算符。 STL 实际上有不同的 iterator
和 const_iterator
类型。 const_iterator
体现了您所描述的概念:迭代器本身是可变的,但它指向的是 const
.
我建议您效仿并创建一个单独的 ConstIterator
class.