C++结构体部分显式构造导致编译异常分析

今天调试了一段代码如下

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

猜你喜欢

转载自blog.csdn.net/weixin_45119096/article/details/132194750
今日推荐