gpt4 book ai didi

c++ - 如何正确使用 `std::vector.back()`?

转载 作者:行者123 更新时间:2023-12-02 01:45:54 25 4
gpt4 key购买 nike

我的代码中有一个我不太明白的错误。根据文档,std::vector.back() 返回对容器中最后一个元素的引用,所以这就是我所做的:( live here )

#include <iostream>
#include <vector>

class Foo {
public:
Foo(int id) : id(id) {
std::cout << "foo " << id << " constructed" << std::endl;
}
~Foo() {
std::cout << "foo " << id << " destructed" << std::endl;
}

int id;
};

int main() {
std::vector<Foo> foos;

for (int i = 0; i < 2; i++) {
foos.emplace_back(i); // construct foo in place

auto& foo = foos.back();
std::cout << "Play with " << foo.id << std::endl;
}

for (auto&& foo : foos) {
std::cout << "I'm foo " << foo.id << std::endl;
}

return 0;
}

产生以下输出:

foo 0 constructed
Play with 0
foo 1 constructed
foo 0 destructed
Play with 1
I'm foo 0
I'm foo 1
foo 0 destructed
foo 1 destructed

那么,在构造 Foo 的第二个实例之后,第一个实例就被破坏了,为什么?因为 auto& foo 超出了范围?但是当我打印 foos vector 时,它仍然有两个 foo,真是令人惊讶!乍一看,好像 foos.back() 正在制作拷贝,但事实并非如此。我真正不明白的是,怎么可能构造函数被调用两次而析构函数被调用3次,它们不应该总是成对出现吗?

最佳答案

这里发生的情况是,当您 .emplace_back(1) 时,std::vector 没有足够的空间容纳两个元素,因此它必须重新分配、复制/将所有现有元素移动到新分配,然后 emplace_back 新分配。因此,您会看到旧分配中唯一存在的元素被销毁。

如果您在循环之前.reserve(2),这种情况就会消失:https://godbolt.org/z/oj8fWhznP

foo 0 constructed
Play with 0
foo 1 constructed
Play with 1
I'm foo 0
I'm foo 1
foo 0 destructed
foo 1 destructed

您还可以使用.capacity()来检查分配的大小,这确实证实了理论:https://godbolt.org/z/a88xfqa7f

--- 0 ---
capacity: 0
foo 0 constructed
capacity: 1
Play with 0
--- 1 ---
capacity: 1
foo 1 constructed
foo 0 destructed
capacity: 2
Play with 1

添加移动/复制构造函数和赋值运算符的日志记录定义可能会让您更好地了解 std::vector 内部正在执行的操作。

关于c++ - 如何正确使用 `std::vector.back()`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70908027/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com