【发布时间】:2010-11-14 08:00:12
【问题描述】:
我是在阅读 Effective C++(第三版)第 11 条后写下这段代码的。
#include <iostream>
using namespace std;
#define MAX_COLORS 20
class Widget
{
public:
Widget ( int seed );
~Widget ( );
Widget& operator=( const Widget& rhs );
void ToString ( );
private:
Widget& SelfAssignmentUnsafe ( const Widget& rhs );
Widget& SelfAssignmentSafe ( const Widget& rhs );
Widget& SelfAssignmentAndExceptionSafe ( const Widget& rhs );
void MakeDeepCopy ( const Widget& rhs );
int *colorPallete;
};
void Widget::ToString()
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
cout << "colorPallete[" << i << "]: " << colorPallete[i] << endl;
}
}
Widget::Widget ( int seed ):
colorPallete ( new int[MAX_COLORS])
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
colorPallete[i] = seed + i;
}
}
Widget& Widget::operator=( const Widget& rhs )
{
// return SelfAssignmentUnsafe ( rhs );
// return SelfAssignmentSafe( rhs );
return SelfAssignmentAndExceptionSafe ( rhs );
}
Widget& Widget::SelfAssignmentUnsafe ( const Widget& rhs )
{
delete[] colorPallete;
colorPallete = 0;
MakeDeepCopy( rhs );
return *this;
}
Widget& Widget::SelfAssignmentSafe ( const Widget& rhs )
{
if ( this == &rhs ) return *this;
delete[] colorPallete;
colorPallete = 0;
MakeDeepCopy ( rhs );
return *this;
}
void Widget::MakeDeepCopy ( const Widget& rhs )
{
int i = 0;
colorPallete = new int [MAX_COLORS];
for ( i = 0;i < MAX_COLORS; i++ )
{
colorPallete[i] = rhs.colorPallete[i];
}
}
Widget& Widget::SelfAssignmentAndExceptionSafe ( const Widget& rhs )
{
int *origColorPallete = colorPallete;
MakeDeepCopy ( rhs );
delete[] origColorPallete;
origColorPallete = 0;
return *this;
}
Widget::~Widget()
{
delete[] colorPallete;
}
int main()
{
Widget b(10);
Widget a(20);
b.ToString();
b = b;
cout << endl << "After: " << endl;
b.ToString();
}
作者谈到在赋值运算符中处理对self的赋值:
Widget a(10);
a = a;
我从 Widget 的赋值运算符调用 Widget::SelfAssignmentAndExceptionSafe。
在 Widget::SelfAssignmentAndExceptionSafe 中的想法是将 colorPallete 指针保存在 origColorPallete 中。然后制作 rhs.colorPallete 的深层副本。当复制成功时,我删除原始指针并返回对自身的引用。
上述机制应该是自赋值和异常安全的。
但是,Widget::SelfAssignmentAndExceptionSafe 无法正确处理对 self 的分配。 colorPallete 数组包含自赋值后的垃圾。它对其他情况的处理非常好。
为什么会这样?
请帮忙。
[编辑:检查所有答案后]
感谢您的回答。我已经更新了 MakeDeepCopy 方法,该示例现在可以正常工作了。下面,我粘贴了更新后的代码:
#include <iostream>
using namespace std;
#define MAX_COLORS 20
class Widget
{
public:
Widget ( int seed );
~Widget ( );
Widget& operator=( const Widget& rhs );
void ToString ( );
private:
Widget( Widget& rhs );
Widget& SelfAssignmentUnsafe ( const Widget& rhs );
Widget& SelfAssignmentSafe ( const Widget& rhs );
Widget& SelfAssignmentAndExceptionSafe ( const Widget& rhs );
void MakeDeepCopy ( const int* rhs );
int *colorPallete;
};
void Widget::ToString()
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
cout << "colorPallete[" << i << "]: " << colorPallete[i] << endl;
}
}
Widget::Widget ( int seed ):
colorPallete ( new int[MAX_COLORS])
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
colorPallete[i] = seed + i;
}
}
Widget& Widget::operator=( const Widget& rhs )
{
// return SelfAssignmentUnsafe ( rhs );
// return SelfAssignmentSafe( rhs );
return SelfAssignmentAndExceptionSafe ( rhs );
}
Widget& Widget::SelfAssignmentUnsafe ( const Widget& rhs )
{
delete[] colorPallete;
colorPallete = 0;
MakeDeepCopy( rhs.colorPallete );
return *this;
}
Widget& Widget::SelfAssignmentSafe ( const Widget& rhs )
{
if ( this == &rhs ) return *this;
delete[] colorPallete;
colorPallete = 0;
MakeDeepCopy ( rhs.colorPallete );
return *this;
}
void Widget::MakeDeepCopy ( const int* rhs )
{
int i = 0;
colorPallete = new int [MAX_COLORS];
for ( i = 0;i < MAX_COLORS; i++ )
{
colorPallete[i] = rhs[i];
}
}
Widget& Widget::SelfAssignmentAndExceptionSafe ( const Widget& rhs )
{
int *origColorPallete = colorPallete;
MakeDeepCopy ( rhs.colorPallete );
delete[] origColorPallete;
origColorPallete = 0;
return *this;
}
Widget::~Widget()
{
delete[] colorPallete;
}
int main()
{
Widget b(10);
Widget a(20);
b.ToString();
b = b;
cout << endl << "After: " << endl;
b.ToString();
}
[编辑:根据查尔斯的回应修改代码]
这个想法是实现“复制和交换”习语,以使代码既自分配又安全。请注意,复制仅在复制构造函数中实现。如果复制成功,我们交换赋值运算符。
对上一次更新的另一个改进是 MakeDeepCopy 的界面依赖于正确的使用。在调用 MakeDeepCopy 之前,我们必须存储/删除 colorPallete 指针。现在不存在这样的依赖关系。
#include <iostream>
using namespace std;
#define MAX_COLORS 20
class Widget
{
public:
Widget ( int seed );
~Widget ( );
Widget& operator=( const Widget& rhs );
void ToString ( );
Widget( const Widget& rhs );
private:
int *colorPallete;
};
void Widget::ToString()
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
cout << "colorPallete[" << i << "]: " << colorPallete[i] << endl;
}
}
Widget::Widget ( int seed ):
colorPallete ( new int[MAX_COLORS])
{
int i = 0;
for ( i = 0; i < MAX_COLORS; i++ )
{
colorPallete[i] = seed + i;
}
}
Widget::Widget( const Widget& rhs ):
colorPallete( new int[MAX_COLORS] )
{
std::copy ( rhs.colorPallete, rhs.colorPallete + MAX_COLORS, colorPallete );
}
Widget& Widget::operator=( const Widget& rhs )
{
Widget tmp(rhs);
std::swap ( colorPallete, tmp.colorPallete );
return *this;
}
Widget::~Widget()
{
delete[] colorPallete;
}
int main()
{
Widget b(10);
Widget a(20);
b.ToString();
b = b;
cout << endl << "After: " << endl;
b.ToString();
}
【问题讨论】:
-
+1 用于实际编译和演示问题的示例代码。
-
拼写为“调色板”:一个 L,两个 T。
-
哎呀!我将永远是一个阅读障碍者