C++范围for循环中begin()能否返回不可拷贝迭代器的引用?
结论:范围for循环要求迭代器可拷贝,附不可拷贝核心对象的替代方案
先给你明确结论:你说得没错——用于范围for循环的迭代器必须是可拷贝构造的,这可不是g++ 9.3.0的特殊要求,而是C++标准对迭代器的硬性规定之一。
为什么你的代码会编译失败?
你写的代码里,把Iterator的拷贝构造函数直接delete了,但范围for循环在编译阶段会被编译器展开成类似这样的代码:
auto __it_begin = container.begin(); auto __it_end = container.end(); for (; __it_begin != __it_end; ++__it_begin) { const Iterator& iterator = *__it_begin; // 你的循环体逻辑 }
这里的auto __it_begin = container.begin();是关键:哪怕begin()返回的是引用,__it_begin作为一个独立的迭代器对象,必须通过拷贝构造来初始化——这一步直接触发了你的删除拷贝构造函数的编译错误。
想保护核心对象不被拷贝?试试这个方案
如果你确实想避免核心对象被拷贝,但又要满足迭代器的可拷贝要求,可以像Artyer提出的那样,封装一个持有容器指针/引用的迭代器类。这个迭代器本身是可拷贝的,但它内部只存储指向目标对象的指针,不会拷贝你真正想保护的核心元素。
示例代码如下:
struct Element {}; struct Container { Element element; struct Iterator { Container* c; Iterator(Container* c) : c(c) {} bool operator != (const Iterator& end) const { return c != end.c; } void operator ++ () { c = nullptr; } const Element& operator * () const { return c->element; } }; Iterator begin() { return Iterator(this); } Iterator end() { return Iterator(nullptr); } }; #include <stdio.h> int main () { Container c; printf ( "main %p\n", & c.element ); for ( const Element & e : c ) { printf ( "loop %p\n", & e ); } return 0; }
这个方案的核心逻辑是:
- 迭代器仅保存容器的指针,拷贝迭代器时只是拷贝指针,完全不会触碰
Element这类核心对象 - 通过指针状态控制迭代流程:
begin()返回指向当前容器的迭代器,end()返回空指针迭代器,递增时将指针置空表示迭代结束 - 既满足了C++对迭代器可拷贝的标准要求,又达到了你不想拷贝核心对象的初衷
内容的提问来源于stack exchange,提问作者mpb
相关产品推荐
相关产品推荐

