简体   繁体   中英

What can cause an implicit/default copy constructor to fail on a POD struct?

Update:

Thanks to @user2079303 for the Coliru resource and test code.

I've now got code that demonstrates this issue when compiled with VS2013 - it works fine when compiled on Coliru, so it's definitely as VS2013 compiler problem. As @user2079303 correctly suggested the previous code did NOT have the error.

The issue appears to be having a wrapper function around the array access before the copy to result:

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;
}

Here's a link to Coliru that has the modified source: Coliru Example

If run on Coliru it works fine, BUT when build with VS2013 in a C++ console app with CLR turned on it fails.


I'm struggling to explain some very strange behaviour that I've been seeing with copy constructors in VS2013, and I'm wondering if any of you have seen anything similar and can shed any light on it.

I've been wrapping a 3rd party C++ DLL using SWIG and was having problems with getting valid data out of a specific structure.

The 3rd party DLL exposes all of its data via POD structures defined in the API header file and most where working fine - giving me valid data, however, a few appeared broken and were producing invalid data.

After much debugging eventually I discovered that replacing the compiler generated copy constructor with my own that simply uses memcpy solves the problem.

The question is really about what can possible be going wrong?

How can a compiler generated copy constructor be going wrong without generating any errors?

As far as I can tell there's nothing particularly different about the struct that doesn't work when compared to one that does... so I'm happy to confess to being highly confused.

Here's the structure in question, and the structures it contains, with my added copy constructor:

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));
   }
};

When the constructors are commented out, the struct is not copied correctly, when commented back in things work fine.

Can anyone out there explain this? I can't.

As requested here's the code that actually uses the copy constructor:

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;
}

This is code generated by SWIG, and is part of a managed C++ wrapper class for the native 3rd party DLL.

In the VS2013 debugger, I can see that arg1 is a valid array of ConGroup structures that contain valid data and doing manual pointer arithmetic in the memory window allowed me to check that for a number of the array contents.

As it happens I've worked around the issue by changing the code above to the following, which removes the copying entirely:

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;
}

That code works perfectly, so valid data does exist at the correct locations, hence I believe the issue must be a copy constructor problem...

Time to close this question.

It seems the issue here is entirely related to having the CLR enabled on a C++ project. Enabling the CLR appears the alter the way the copy default constructors work within the C++ code when using Visual Studio 2013 and 2015.

Given that could be better phrased as a new question I'm closing this one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM