swap函数用于置换两对象的值,标准库中如下实现:
template
<
typename
T
>
void
swap
(
T
&
ta
,
T
&
tb
)
{
T
temp
(
ta
);
ta
=
tb
;
tb
=
temp
;
}
正确调用此模板方法,只需实现class的拷贝构造函数和赋值构造函数即可。但此处若
是pimpl(pointer to implement)的实现方式,若单纯使用上述方式每次拷贝的都是整个对象,现实现只交换指针的swap。
class
WidgetImpl
{
public
:
WidgetImpl
(
int
aa
=0,
int
bb
=0,
int
cc
=0)
:
a
(
aa
),
b
(
bb
),
c
(
cc
)
{
}
WidgetImpl
(
const
WidgetImpl
&
rhs
)
:
a
(
rhs
.
a
),
b
(
rhs
.
b
),
c
(
rhs
.
c
)
{
}
WidgetImpl
&
operator
=(
const
WidgetImpl
&
rhs
)
{
a
=
rhs
.
a
;
b
=
rhs
.
b
;
c
=
rhs
.
c
;
return
*
this
;
}
private
:
int
a
,
b
,
c
;
};
class
Widget
{
public
:
Widget
(
WidgetImpl
*
p
= 0) :
pImpl
(
p
)
{
}
Widget
(
const
Widget
&
rhs
):
pImpl
(
pImpl
=
new
WidgetImpl
())
//
牢记,否则为空指针
{
*
pImpl
= *
rhs
.
pImpl
;
//
复制所指的对象
,
深拷贝
}
Widget
&
operator
=(
const
Widget
&
rhs
)
{
//
此处应该避免自我复制
pImpl
=
new
WidgetImpl
();
*
pImpl
= *
rhs
.
pImpl
;
//
复制所指的对象
return
*
this
;
}
std
::
ostream
&
print
(
std
::
ostream
& =
std
::
cout
)
const
;
~
Widget
()
{
if
(
pImpl
!=
NULL
)
delete
pImpl
;
}
//member swap
void
swap
(
Widget
&
other
)
{
using
std
::
swap
;
std
::
cout
<<
pImpl
<<
" "
<<
other
.
pImpl
<<
std
::
endl
;
swap
(
pImpl
,
other
.
pImpl
);
}
private
:
WidgetImpl
*
pImpl
;
};
现有一种方式,即std::swap 的一个特化版本,实现如下:
namespace
std
{
using
namespace
WidgetStuff
;
template
<>
void
swap
<
Widget
>(
Widget
&
a
,
Widget
&
b
)
{
swap(a.pImpl, b.pImpl);
}
}
此实现不可编译,swap中访问了Widget的私有成员。我们令Widget声明一个名为swap的public成员函数做真正的置换工作,然后将std::swap特化,令它调用该成员函数:
//
函数模板特化
namespace
std
{
using
namespace
WidgetStuff
;
template
<>
void
swap
<
Widget
>(
Widget
&
a
,
Widget
&
b
)
{
a
.
swap
(
b
);
}
}
此种做法可行,但若Widget和WidgetImpl都是template class而非template,我们想这样写:
namespace
std
{
using
namespace
WidgetStuff
;
template
<typename T>
void
swap
<
Widget<T>
>(
Widget<T>
&
a
,
Widget<T>
&
b
)
{
a
.
swap
(
b
);
}
}
此处不可编译,因为函数模板不支持部分特化。
还可如下写:
namespace
std
{
using
namespace
WidgetStuff
;
template
<typename T>
void
swap
(
Widget<T>
&
a
,
Widget<T>
&
b
)
{
a
.
swap
(
b
);
}
}
此处作为swap的一个重载版本,但std中不允许添加函数。此方法亦不可行。
我们的做法是定义一个non-member swap让他调用member swap.在我们的命名空间WidgetStuff中这样写:
template
<typename T>
void
swap
(
Widget<T>
&
a
,
Widget<T>
&
b
)
{
a
.
swap
(
b
);
}
具体实现代码见附件。
令swap可以用在赋值构造函数中防止自我复制。
class Widget {
...
void swap(Widget& rhs);
...
};
Widget& Widget::operator=(const Widget& rhs)
{
Widget tmp(rhs);
swap(tmp);
return *this;
}