正确 std::map 行为的结构的默认构造函数

Default constructor of the structure for correct std::map behaviour

为什么我们需要为正确的 std::map 行为定义默认构造函数 TConcrete()? 没有它我得到以下内容:

 >note: see reference to function template instantiation 'std::pair<const _Kty,_Ty>::pair<std::tuple<std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&>,std::tuple<>,0,>(_Tuple1 &,_Tuple2 &,std::integer_sequence<unsigned int,0>,std::integer_sequence<::size_t>)' being compiled
1>        with
1>        [
1>            _Kty=std::string,
1>            _Ty=TConcrete,
1>            _Tuple1=std::tuple<std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&>,
1>            _Tuple2=std::tuple<>
1>        ]

这是我的代码。我正在使用 C++03.

main.cpp

#include<iostream>
#include"TBuilder.h"

using namespace std;

int main()
{
    TBuilder builder = TBuilder();
    cout << builder.Get_Eb("B25");
    cin.get();
    return 0;
}

TBuilder.h

#pragma once
#include"TConcrete.h"

class TBuilder {
private:
    TConcreteData concrete_data;
public:
         TBuilder();
    double Get_Eb(string);
};

TBuilder.cpp

#include"TBuilder.h"

TBuilder::TBuilder()
{
    TConcrete B25 = TConcrete( "B25",2000,20,2 );
    concrete_data["B25"] = B25;
}

double TBuilder::Get_Eb(string grade0)
{
    return concrete_data[grade0].E_b;
}

TConcrete.h

#pragma once

#include<map>
#include<string>
#include "main.h"

using namespace std;

struct TConcrete {
    string grade;
    double E_b, R_b, R_bt;
    TConcrete();
    TConcrete(string, double,double,double);
};   
typedef map<string, TConcrete> TConcreteData;

TConcrete.cpp

#include "TConcrete.h"

TConcrete::TConcrete()
{
}

TConcrete::TConcrete(string grade0, double E_b0, double R_b0, double Rb_t0)
{
    grade = grade0;
    E_b = E_b0;
    R_b = R_b0;
    R_bt = R_b0;
}   

我阅读了 讨论,但使用 insert() 也需要默认构造函数。请参阅带有 insert().

的代码

TConcrete.h(修改为insert()

#pragma once

#include<map>
#include<string>
#include "main.h"
#include<utility>

using namespace std;

struct TConcrete {
    string grade;
    double E_b, R_b, R_bt;
    TConcrete();
    TConcrete(string, double,double,double);
};
typedef map<string, TConcrete> TConcreteData;
typedef pair<string, TConcrete> TConcreteDataItem;

TBuilder.cpp(修改为insert()

#include"TBuilder.h"

TBuilder::TBuilder()
{
    TConcrete B25 = TConcrete( "B25",2000,20,2 );
    concrete_data.insert(TConcreteDataItem("B25",B25));
}

double TBuilder::Get_Eb(string grade0)
{
    return concrete_data[grade0].E_b;
}

std::map::operator[] 搜索指定的键,如果没有找到则为该键插入一个新的 default-constructed 值。

因此,语句 concrete_data["B25"] 总是 returns 有效的 TConcrete& 引用,这意味着如果需要,在允许您分配之前默认构造一个 TConcrete 对象您的 B25 变量设置为 found/inserted 值。

如果您想在地图中添加新键而不搜索该键是否已存在,请改用 std::map::insert()std::map::emplace()

TConcrete B25( "B25", 2000, 20, 2 );
concrete_data.insert(std::make_pair("B25", B25));
TConcrete B25( "B25", 2000, 20, 2 );
concrete_data.emplace("B25", B25);

您需要默认构造函数,因为您使用的方式 std::map 需要它可能创建对象。如果您不以这种方式使用它,则不需要默认构造函数。

由于缺少默认构造函数,此代码将无法编译:

#include <map>

struct Struct
{
    Struct(int) {}
};

int main()
{
    std::map<std::string, Struct > m;
    m["1"] = Struct(1);
    Struct& s = m["1"];
}

[] 运算符 returns 对现有值的引用。如果该值不存在,则创建一个新值(使用默认构造函数)并返回对该值的引用。第一条语句可能看起来不像正在发生的事情,但实际上等同于:

Struct& s = m["1"];
s = Struct(1);

如果您使用 findinsert,则不需要默认构造函数:

int main()
{
    std::map<std::string, Struct > m;
    m.insert(std::make_pair(std::string("1"), Struct(1)));
    auto it = m.find("1");
    if (it != m.end())
    {
        Struct& s = it->second;
    }
}