今天调试了一段代码如下
#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//10x5B, 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, //ver0x00,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)的时候,要么选择不默认任何成员,这样类会自动调用默认构造,默认构造会初始化成员变量,如果有部分不默认,那就写一个显示构造接口,或者使用数组批量给实例化(部分成员)对象赋值的时候,确保没有部分对象已经赋值了。