簡體   English   中英

如何正確使用`std::vector.back()`?

[英]How to use `std::vector.back()` correctly?

我的代碼中有一個我不太理解的錯誤。 根據文檔, std::vector.back()返回對容器中最后一個元素的引用,所以這就是我所做的:(住在這里

#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;
}

產生以下 output:

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超出了 scope? 但是當我打印foos向量時,它仍然有兩個 foos,真是令人驚訝! 乍一看,似乎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在內部做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM