VS2005からVS2010にいくつかのコードを移植し、メモリの破損が発生し始めたため、今日この問題を検討していました。これは、最適化(マップルックアップを実行するときにコピーを回避するため)が移動セマンティクスを使用してC++11に変換されなかったためであることが判明しました。
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;
}
マップキーがすでに存在する場合に不要なヒープ割り当てを回避したいというコンテキストでした。したがって、CShallowCopyクラスを使用して初期ルックアップを実行し、これが挿入の場合はコピーされます。問題は、このアプローチが移動セマンティクスでは機能しないことです。