I was looking at this very issue today, because we've ported some code from VS2005 into VS2010 and started seeing memory corruption. It turned out to be because an optimization (to avoid copying when doing a map lookup) didn't translate into C++11 with move semantics.
class CDeepCopy
{
protected:
char* m_pStr;
size_t m_length;
void clone( size_t length, const char* pStr )
{
m_length = length;
m_pStr = new char [m_length+1];
for ( size_t i = 0; i < length; ++i )
{
m_pStr[i] = pStr[i];
}
m_pStr[length] = '\0';
}
public:
CDeepCopy() : m_pStr( nullptr ), m_length( 0 )
{
}
CDeepCopy( const std::string& str )
{
clone( str.length(), str.c_str() );
}
CDeepCopy( const CDeepCopy& rhs )
{
clone( rhs.m_length, rhs.m_pStr );
}
CDeepCopy& operator=( const CDeepCopy& rhs )
{
if (this == &rhs)
return *this;
clone( rhs.m_length, rhs.m_pStr );
return *this;
}
bool operator<( const CDeepCopy& rhs ) const
{
if (m_length < rhs.m_length)
return true;
else if (rhs.m_length < m_length)
return false;
return strcmp( m_pStr, rhs.m_pStr ) < 0;
}
virtual ~CDeepCopy()
{
delete [] m_pStr;
}
};
class CShallowCopy : public CDeepCopy
{
public:
CShallowCopy( const std::string& str ) : CDeepCopy()
{
m_pStr = const_cast<char*>(str.c_str());
m_length = str.length();
}
~CShallowCopy()
{
m_pStr = nullptr;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::map<CDeepCopy, int> entries;
std::string hello( "Hello" );
CDeepCopy key( hello );
entries[key] = 1;
// Named variable - ok
CShallowCopy key2( hello );
entries[key2] = 2;
// Unnamed variable - Oops, calls CDeepCopy( CDeepCopy&& )
entries[ CShallowCopy( hello ) ] = 3;
return 0;
}
The context was that we wanted to avoid unnecessary heap allocations in the event that the map key already existed - hence, the CShallowCopy class was used to do the initial lookup, then it would be copied if this was an insertion. The problem is that this approach doesn't work with move semantics.