我正在实现(用于训练目的)一个冒泡排序模板函数:
template<typename iterInput,
typename predicate>
void BubbleSort(iterInput first1,iterInput last1,predicate func)
{
bool swapped(false);
do
{
swapped = false;
iterInput begin = first1;
iterInput beginMinus = first1;
++begin;
for (;begin != last1; begin++,beginMinus++)
{
if (func(*beginMinus,*begin) )
{
std::swap(*beginMinus,*begin);
swapped = true;
}
}
}
while(swapped);
}
当我意识到这个函数对于没有赋值运算符的类不起作用时,比如下面这个类(请原谅我的糟糕命名):
class NoCopyable
{
public:
explicit NoCopyable(int value) : value_(value) {}
NoCopyable(const NoCopyable& other) : value_(other.value_) {}
~NoCopyable() {}
bool operator<(const NoCopyable& other) { return value_ < other.value_; }
void setValue(int value) { value_ = value; }
std::ostream& print(std::ostream& os) const { return os << value_; }
private:
NoCopyable& operator=(const NoCopyable& other);
int value_;
};
std::ostream& operator<<(std::ostream& os, const NoCopyable& obj)
{
return obj.print(os);
}
struct PrintNoCopyable
{
void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; }
};
编译器报错:错误 C2248: 'NoCopyable::operator =' : 无法访问类中声明的私有成员
因此,我稍微修改了代码,使用了我的版本的交换函数而不是 std::swap 函数,以下是代码:
template<typename T1,
typename T2>
void noAssignmentSwap(T1& t1,T2& t2)
{
T1 temp(t1);
t1.~T1();
new (&t1) T1(t2);
t2.~T2();
new (&t2) T2(temp);
}
代码编译并给出正确的结果。然而,我不完全确定,我记得Sutter的一篇文章建议避免玩弄对象的生命周期。该文章只是在没有给出任何真正原因的情况下警告您不要玩火。如果T1或T2的复制构造函数可能会抛出异常,我可以看到异常安全性存在问题。但是,如果允许赋值运算符抛出异常,则标准版本也存在同样的问题。
现在的问题是,您能否看到此版本swap可能存在的任何潜在缺陷?
干杯