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.
const
", they said, "we'll just not modify objects that we're not supposed to". – Condescendconst
to help the compiler enforce that. This is not the same thing (I suspected I would get a reply like that). Explicitly declaring that you want a copyable but not movable class? What's bad about that except it may just be unnecessary? In fact, your answer seems to just support what I said... – Equi