【问题标题】:Default constructor of the structure for correct std::map behaviour用于正确 std::map 行为的结构的默认构造函数
【发布时间】:2019-08-29 06:49:53
【问题描述】:

为什么我们需要为正确的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

ma​​in.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;
}   

我阅读了std::map calls default constructor on [], copy constructor on insert() 的讨论,但使用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在哪里?
  • 此代码不完整 - 您没有显示任何 std::map 声明。但是假设 TConcreteData 是 std::map 的某种类型别名,如果访问的键不存在,std::map::operator[] 会在映射中插入一个新对象。如果您不希望您的 TConcrete 类是默认可构造的,则必须使用其他函数,例如 std::map::emplace
  • 什么是 TConcreteData?
  • @JamesPicone 你是对的。从 VS 移动代码时,我错过了 TConcrete.h 中的 typedef。已更正。
  • @Fëamarto 查看我对 JamesPicone 的回答

标签: c++ c++03


【解决方案1】:

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

因此,concrete_data["B25"] 语句始终返回有效的TConcrete&amp; 引用,这意味着在允许您将B25 变量分配给找到/插入的值之前,如果需要,默认构造一个TConcrete 对象。

如果您想在地图中添加新键而不搜索该键是否已存在,请改用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::insert(),它不起作用。查看更新后的问题。
  • @maksim_volodin insert() 不需要您的 TConcrete 类具有默认构造函数。如果在未定义默认构造函数时对该语句出现错误,请显示该错误。但是,concrete_data[grade0] 确实需要默认构造函数
  • @Remi Lebeau 正如 Alan Birtles 所说的那样 “您仍在 Get_Eb 中使用 [] 运算符,除非您的类型是默认可构造的,否则您不能使用该运算符” i> 现在我想这个主题对我来说很清楚了。
【解决方案2】:

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

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

#include <map>

struct Struct
{
    Struct(int) {}
};

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

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

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

【讨论】:

  • 我用insert() 更新了这个问题。可以看看吗?
  • @maksim_volodin 你还在Get_Eb 中使用[] 运算符,除非你的类型是默认可构造的,否则你不能使用该运算符
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 2017-10-26
  • 2020-05-19
  • 2017-05-31
  • 2018-11-30
  • 2021-01-01
相关资源
最近更新 更多