什么会导致 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++ 代码中的工作方式。

考虑到可以更好地表述为一个新问题,我将关闭这个问题。