如果我在一个容器的后面插入一个元素(例如emplace_back()
),新元素是否总是保证在前面的::end()位置?
比较以下示例:在这里,这是有效的,因为我可以将迭代器传递给新插入的实体对象,该对象又依赖于它来向控制台输出“Hello World”。我想知道这是否保证对每个容器都有效。
EDIT:正如注解中所指出的,由于插入后的重分配,std::vector和consort已经退出。但我仍然想知道是否所有containers在插入后都是迭代器保留的。
演示
#include <cstdio>
#include <functional>
#include <list>
struct entity
{
entity(std::function<void()> fn)
: fn_( fn )
{ }
auto print()
{
printf("Hello World!");
}
auto operator()() -> void {
fn_();
}
std::function<void()> fn_;
};
using list_t = std::list<entity>;
using iterator_t = list_t::iterator;
int main()
{
list_t mylist;
mylist.emplace_back([it = mylist.end()]{ it->print(); });
for (auto& item : mylist) {
item();
}
}
2条答案
按热度按时间afdcj2ne1#
在你所显示的代码中,lambda将在lambda被示例化时捕获结束迭代器。由于结束迭代器没有指向一个有效的节点,所以你不允许取消引用它。重要的是要理解,你的lambda已经通过值捕获了结束迭代器,并且这个迭代器将永远不会自己更新。这适用于标准库中的每个容器,我猜它甚至可以容纳野外的每一个自定义容器。
当调用lambda时你取消引用了结束迭代器,这样做你就处于未定义的行为状态。你的程序是病态的,没有输出是有保证的。
nwnhqdif2#
“......当它可能不再是占位符时”(从评论到原始问题)是不正确的。
这里,输出为
基本上我的观点是,默认参数是在函数被调用时赋值的,因此,在您的示例中,
it
被赋值给列表的end
迭代器,因此it->print()
是未定义的行为,因为您使用it->print()
解引用end
迭代器(您可以将it->print()
视为(*it).print()
,但这可能是显而易见的)。