我今天正在研究这个问题,因为我们已经将一些代码从 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 类用于进行初始查找,然后如果这是插入,它将被复制。问题是这种方法不适用于移动语义。