c++ - 在结构的 STL 映射中,为什么 "[ ]"运算符会导致结构的 dtor 被额外调用 2 次?

标签 c++ stl constructor copy-constructor temporary-objects

我创建了一个简单的测试用例,展示了我在处理的较大代码库中注意到的奇怪行为。这个测试用例如下。我依靠 STL Map 的“[]”运算符在此类结构的映射中创建一个指向结构的指针。在下面的测试用例中,行...

TestStruct *thisTestStruct = &testStructMap["test"];

...获取指针(并在 map 中创建一个新条目)。我注意到的奇怪之处在于,这一行不仅导致在映射中创建一个新条目(因为“[]”运算符),而且由于某种原因它导致结构的析构函数被额外调用两次。我显然遗漏了一些东西 - 非常感谢任何帮助! 谢谢!

#include <iostream>
#include <string>
#include <map>

using namespace std;
struct TestStruct;

int main (int argc, char * const argv[]) {

    map<string, TestStruct> testStructMap;

    std::cout << "Marker One\n";

    //why does this line cause "~TestStruct()" to be invoked twice?
    TestStruct *thisTestStruct = &testStructMap["test"];

    std::cout << "Marker Two\n";

    return 0;
}

struct TestStruct{
    TestStruct(){
        std::cout << "TestStruct Constructor!\n";
    }

    ~TestStruct(){
        std::cout << "TestStruct Destructor!\n";
    }
};

上面的代码输出如下...

/*
Marker One
TestStruct Constructor!             //makes sense
TestStruct Destructor!               //<---why?
TestStruct Destructor!               //<---god why?
Marker Two
TestStruct Destructor!               //makes sense
*/

...但我不明白是什么导致了 TestStruct 的析构函数的前两次调用? (我认为最后的析构函数调用是有意义的,因为 testStructMap 超出了范围。)

最佳答案

std::map<>::operator[] 的功能相当于

(*((std::map<>::insert(std::make_pair(x, T()))).first)).second

表达式,如语言规范中所指定。如您所见,这涉及默认构造类型为 T 的临时对象。 , 将其复制到 std::pair对象,稍后将(再次)复制到 map 的新元素中(假设它不存在)。很明显,这会产生一些中间T对象。这些中间物体的破坏是您在实验中观察到的。你错过了他们的 build ,因为你没有从你类(class)的复制构造者那里产生任何反馈。

中间对象的确切数量可能取决于编译器优化功能,因此结果可能会有所不同。

关于c++ - 在结构的 STL 映射中,为什么 "[ ]"运算符会导致结构的 dtor 被额外调用 2 次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4017892/

相关文章:

c++ - 如何在 C++ 中向下转换以从父实例调用子函数?

c++ - STL list::splice - 迭代器有效性

c++ - c++17 map::extract 方法在 macOS 上可用吗?

C++ - 创建一个带有赋值而不是初始化的 vector <vector<double>>矩阵

c++ - 不存在从 "test *"转换为 "test"的合适构造函数,构造函数,

c++ - 如何使用 QDataStream 从文件中读取二进制数据?

c++ - va_start() 修改堆栈

c++ - forward_list 迭代器稳定吗?

java - 在赋值上复制构造函数

c++ - QtCreator 和 Poco 无法在 Linux 上编译项目