什么会导致 implicit/default 复制构造函数在 POD 结构上失败?
What can cause an implicit/default copy constructor to fail on a POD struct?
更新:
感谢@user2079303 提供 Coliru 资源和测试代码。
我现在得到的代码在用 VS2013 编译时演示了这个问题 - 在 Coliru 上编译时它工作正常,所以它肯定是 VS2013 编译器问题。正如@user2079303 正确建议前面的代码没有错误。
问题似乎是在复制到结果之前围绕数组访问有一个包装函数:
SWIGINTERN ConGroup ConGroupArray_getitem(ConGroup *self, int index){
return self[index];
}
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult;
ConGroup *arg1 = (ConGroup *)0;
int arg2;
ConGroup result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = ConGroupArray_getitem(arg1, arg2);
// result = arg1[arg2];
jresult = new ConGroup((const ConGroup &)result);
return jresult;
}
这是给 Coliru 的 link 修改后的来源:Coliru Example
如果 运行 在 Coliru 上它工作正常,但是当在 C++ 控制台应用程序中使用 VS2013 构建并打开 CLR 时它会失败。
我正在努力解释我在 VS2013 中看到的复制构造函数的一些非常奇怪的行为,我想知道你们中是否有人看到过类似的事情并且可以阐明它。
我一直在使用 SWIG 包装第 3 方 C++ DLL,但在从特定结构中获取有效数据时遇到问题。
第 3 方 DLL 通过 API 头文件中定义的 POD 结构公开其所有数据,并且大部分工作正常 - 为我提供有效数据,但是,一些似乎损坏并产生无效数据。
经过多次调试,最终我发现将编译器生成的复制构造函数替换为我自己的,只需使用 memcpy 即可解决问题。
真正的问题是什么可能出错?
编译器生成的复制构造函数怎么会出错而不产生任何错误?
据我所知,无效的结构与有效的结构没有什么特别不同...所以我很高兴承认自己非常困惑。
这是有问题的结构及其包含的结构,以及我添加的复制构造函数:
struct ConGroupSec
{
int show,trade;
int execution;
double comm_base;
int comm_type;
int comm_lots;
double comm_agent;
int comm_agent_type;
int spread_diff;
int lot_min,lot_max;
int lot_step;
int ie_deviation;
int confirmation;
int trade_rights;
int ie_quick_mode;
int autocloseout_mode;
double comm_tax;
int comm_agent_lots;
int freemargin_mode;
int reserved[3];
};
struct ConGroupMargin
{
char symbol[12];
double swap_long,swap_short;
double margin_divider;
int reserved[7];
};
struct ConGroup
{
char group[16];
int enable;
int timeout;
int adv_security;
char company[128];
char signature[128];
char support_page[128];
char smtp_server[64];
char smtp_login[32];
char smtp_password[32];
char support_email[64];
char templates[32];
int copies;
int reports;
int default_leverage;
double default_deposit;
int maxsecurities;
ConGroupSec secgroups[32];
ConGroupMargin secmargins[128];
int secmargins_total;
char currency[12];
double credit;
int margin_call;
int margin_mode;
int margin_stopout;
double interestrate;
int use_swap;
int news;
int rights;
int check_ie_prices;
int maxpositions;
int close_reopen;
int hedge_prohibited;
int close_fifo;
int hedge_largeleg;
int unused_rights[2];
char securities_hash[16];
int margin_type;
int archive_period;
int archive_max_balance;
int stopout_skip_hedged;
int archive_pending_period;
UINT news_languages[8];
UINT news_languages_total;
int reserved[17];
ConGroup() {}
ConGroup(const ConGroup& src)
{
memcpy(this, &src, sizeof(ConGroup));
}
};
当构造函数被注释掉时,结构没有被正确复制,当注释回来时一切正常。
有人能解释一下吗?我不能。
根据要求,这里是实际使用复制构造函数的代码:
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult ;
ConGroup *arg1 = (ConGroup *) 0 ;
int arg2 ;
ConGroup result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = arg1[arg2];
jresult = new ConGroup((const ConGroup &)result);
return jresult;
}
这是由 SWIG 生成的代码,是原生第 3 方 DLL 的托管 C++ 包装器 class 的一部分。
在 VS2013 调试器中,我可以看到 arg1 是一个包含有效数据的 ConGroup 结构的有效数组,并且在内存中进行手动指针运算 window 允许我检查数组的一些内容。
碰巧我通过将上面的代码更改为以下代码解决了这个问题,这完全删除了复制:
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult ;
ConGroup *arg1 = (ConGroup *) 0 ;
int arg2 ;
ConGroup* result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = &arg1[arg2];
jresult = (void*)result;
return jresult;
}
该代码完美运行,因此正确位置确实存在有效数据,因此我认为问题一定是复制构造函数问题...
是时候结束这个问题了。
这里的问题似乎完全与在 C++ 项目上启用 CLR 有关。使用 Visual Studio 2013 和 2015 时,启用 CLR 会改变复制默认构造函数在 C++ 代码中的工作方式。
考虑到可以更好地表述为一个新问题,我将关闭这个问题。
更新:
感谢@user2079303 提供 Coliru 资源和测试代码。
我现在得到的代码在用 VS2013 编译时演示了这个问题 - 在 Coliru 上编译时它工作正常,所以它肯定是 VS2013 编译器问题。正如@user2079303 正确建议前面的代码没有错误。
问题似乎是在复制到结果之前围绕数组访问有一个包装函数:
SWIGINTERN ConGroup ConGroupArray_getitem(ConGroup *self, int index){
return self[index];
}
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult;
ConGroup *arg1 = (ConGroup *)0;
int arg2;
ConGroup result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = ConGroupArray_getitem(arg1, arg2);
// result = arg1[arg2];
jresult = new ConGroup((const ConGroup &)result);
return jresult;
}
这是给 Coliru 的 link 修改后的来源:Coliru Example
如果 运行 在 Coliru 上它工作正常,但是当在 C++ 控制台应用程序中使用 VS2013 构建并打开 CLR 时它会失败。
我正在努力解释我在 VS2013 中看到的复制构造函数的一些非常奇怪的行为,我想知道你们中是否有人看到过类似的事情并且可以阐明它。
我一直在使用 SWIG 包装第 3 方 C++ DLL,但在从特定结构中获取有效数据时遇到问题。
第 3 方 DLL 通过 API 头文件中定义的 POD 结构公开其所有数据,并且大部分工作正常 - 为我提供有效数据,但是,一些似乎损坏并产生无效数据。
经过多次调试,最终我发现将编译器生成的复制构造函数替换为我自己的,只需使用 memcpy 即可解决问题。
真正的问题是什么可能出错?
编译器生成的复制构造函数怎么会出错而不产生任何错误?
据我所知,无效的结构与有效的结构没有什么特别不同...所以我很高兴承认自己非常困惑。
这是有问题的结构及其包含的结构,以及我添加的复制构造函数:
struct ConGroupSec
{
int show,trade;
int execution;
double comm_base;
int comm_type;
int comm_lots;
double comm_agent;
int comm_agent_type;
int spread_diff;
int lot_min,lot_max;
int lot_step;
int ie_deviation;
int confirmation;
int trade_rights;
int ie_quick_mode;
int autocloseout_mode;
double comm_tax;
int comm_agent_lots;
int freemargin_mode;
int reserved[3];
};
struct ConGroupMargin
{
char symbol[12];
double swap_long,swap_short;
double margin_divider;
int reserved[7];
};
struct ConGroup
{
char group[16];
int enable;
int timeout;
int adv_security;
char company[128];
char signature[128];
char support_page[128];
char smtp_server[64];
char smtp_login[32];
char smtp_password[32];
char support_email[64];
char templates[32];
int copies;
int reports;
int default_leverage;
double default_deposit;
int maxsecurities;
ConGroupSec secgroups[32];
ConGroupMargin secmargins[128];
int secmargins_total;
char currency[12];
double credit;
int margin_call;
int margin_mode;
int margin_stopout;
double interestrate;
int use_swap;
int news;
int rights;
int check_ie_prices;
int maxpositions;
int close_reopen;
int hedge_prohibited;
int close_fifo;
int hedge_largeleg;
int unused_rights[2];
char securities_hash[16];
int margin_type;
int archive_period;
int archive_max_balance;
int stopout_skip_hedged;
int archive_pending_period;
UINT news_languages[8];
UINT news_languages_total;
int reserved[17];
ConGroup() {}
ConGroup(const ConGroup& src)
{
memcpy(this, &src, sizeof(ConGroup));
}
};
当构造函数被注释掉时,结构没有被正确复制,当注释回来时一切正常。
有人能解释一下吗?我不能。
根据要求,这里是实际使用复制构造函数的代码:
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult ;
ConGroup *arg1 = (ConGroup *) 0 ;
int arg2 ;
ConGroup result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = arg1[arg2];
jresult = new ConGroup((const ConGroup &)result);
return jresult;
}
这是由 SWIG 生成的代码,是原生第 3 方 DLL 的托管 C++ 包装器 class 的一部分。
在 VS2013 调试器中,我可以看到 arg1 是一个包含有效数据的 ConGroup 结构的有效数组,并且在内存中进行手动指针运算 window 允许我检查数组的一些内容。
碰巧我通过将上面的代码更改为以下代码解决了这个问题,这完全删除了复制:
SWIGEXPORT void * SWIGSTDCALL CSharp_ConGroupArray_getitem(void * jarg1, int jarg2) {
void * jresult ;
ConGroup *arg1 = (ConGroup *) 0 ;
int arg2 ;
ConGroup* result;
arg1 = (ConGroup *)jarg1;
arg2 = (int)jarg2;
result = &arg1[arg2];
jresult = (void*)result;
return jresult;
}
该代码完美运行,因此正确位置确实存在有效数据,因此我认为问题一定是复制构造函数问题...
是时候结束这个问题了。
这里的问题似乎完全与在 C++ 项目上启用 CLR 有关。使用 Visual Studio 2013 和 2015 时,启用 CLR 会改变复制默认构造函数在 C++ 代码中的工作方式。
考虑到可以更好地表述为一个新问题,我将关闭这个问题。