今天调试了一段代码如下
#include <iostream>
#include <shared_mutex>
#define SECT_NUM 2
#define DI_HIGH_PERM 2
#define DI_READ 1
#define DI_WRITE 2
#define FMT_BIN 1
#define USER_PATH "d:\\fafiles\\dbtest\\"
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef struct{
WORD wID;
WORD wLen;
WORD wPerm;
WORD wRW;
WORD wOffset;
WORD wWrOp;
WORD wPnNum;
DWORD dwBlockStart;
WORD wBlockLen;
DWORD dwBlockOffset;
DWORD dwBlkIndex;
BYTE bBlkIndexNum;
BYTE bBlkIdIndexNum;
BYTE bInnerIndex;
}TItemDesc;//数据项描述
typedef struct{
char* pszBankName;
char* pszPathName;
char* pszBakPathName;
TItemDesc* pItemDesc;
DWORD dwItemNum;
BYTE* pbDefault;
DWORD dwDefaultSize;
BYTE bVer;
WORD wPnNum;
bool fUpdTime;
WORD wSaveInterv;
std::shared_mutex shared_mtx_BankRW;
BYTE* pbBankData{nullptr};
}TBankCtrl;
TItemDesc g_TCommParaDesc[] = //标准版
{
//1
{0x0001, 10, DI_HIGH_PERM, DI_READ|DI_WRITE, 0, 0, FMT_BIN, 1},//Ver
{0x8010, 6, DI_HIGH_PERM, DI_READ|DI_WRITE, 0, 0, FMT_BIN, 4 },//主站IP地址
{0x8014, 6, DI_HIGH_PERM, DI_READ|DI_WRITE, 0, 0, FMT_BIN, 4 },//
{0x8015, 16, DI_HIGH_PERM, DI_READ|DI_WRITE, 0, 0, FMT_BIN, 4 },//APN
};
BYTE g_bDefaultCommPara[] = //标准版
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //ver
//1
0x5B, 0x07, 94, 240, 13, 10, //0x8010 10.13.240.94 1883 主站地址+端口
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //0x8014 6 代理地址+端口
'C', 'M', 'N', 'E', 'T', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //0x8015 16
};
TItemDesc g_TUnitCommParaDesc[] = //标准版
{
//1
{ 0x0002, 10, DI_HIGH_PERM, DI_READ | DI_WRITE, 0, 0, FMT_BIN, 1 },//Ver
{ 0x8900, 1, DI_HIGH_PERM, DI_READ | DI_WRITE, 0, 0, FMT_BIN, 10 },
{ 0x8901, 1, DI_HIGH_PERM, DI_READ | DI_WRITE, 0, 0, FMT_BIN, 10 },
};
BYTE g_bDefaultUnitCommPara[] = //标准版
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //ver
0x00,
0x00,
};
TBankCtrl g_Bank0Ctrl[SECT_NUM] = {
//SECTION0
{"sect0 Comm para",
USER_PATH"termnComm.cfg",
nullptr,
g_TCommParaDesc,
sizeof(g_TCommParaDesc)/sizeof(TItemDesc),
g_bDefaultCommPara,
sizeof(g_bDefaultCommPara),
0x01,
1,
false,
},
//SECTION1
{ "sect1 Unit-Comm para",
USER_PATH"UnitCommPara.cfg",
nullptr,
g_TUnitCommParaDesc,
sizeof(g_TUnitCommParaDesc)/sizeof(TItemDesc),
g_bDefaultUnitCommPara,
sizeof(g_bDefaultUnitCommPara),
0x01,
1,
false,
},
};
int main()
{
std::cout<<"test db !!"<<std::endl;
getchar();
}
在VS上编译的时候提示:
1>e:\c++test\dbtest\dbtest1.cpp(109): error C2440: “初始化”: 无法从“initializer list”转换为“TBankCtrl”
1> e:\c++test\dbtest\dbtest1.cpp(109): note: 无构造函数可以接受源类型,或构造函数重载决策不明确
========== 全部重新生成: 成功 0 个,失败 1 个,跳过 0 个 ==========
开始的时候以为是结构体和初始化数组不一致,反复对比无误,最后想到,可能是初始化异常导致,此处的初始化,除了在:TBankCtrl g_Bank0Ctrl[SECT_NUM]初始化,实际在结构体内部也有初始化:
将该初始化去掉,改为
编译就正常了。
分析:
这是因为在 C++ 中,当一个结构体或类拥有至少一个构造函数时,它的默认构造函数会被自动生成。默认构造函数会尝试初始化所有成员变量,包括指针类型。对于指针类型,默认构造函数会将其初始化为一个未指定的值,通常是 nullptr。
当你将 TBankCtrl
中的最后一个变量从 BYTE* pbBankData{nullptr};
修改为 BYTE* pbBankData;
时,你就在明示着不需要显式的构造函数,而依赖于编译器生成的默认构造函数,这也就避免了初始化列表中的问题。
结论:
C++使用struct(或者class)的时候,要么选择不默认任何成员,这样类会自动调用默认构造,默认构造会初始化成员变量,如果有部分不默认,那就写一个显示构造接口,或者使用数组批量给实例化(部分成员)对象赋值的时候,确保没有部分对象已经赋值了。