2011-05-27 43 views
5

我正在执行(作训练用途)冒泡排序函数模板:使用无任务交换有没有明显的缺点?

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'; } 
}; 

编译器将引发此错误错误1个错误C2248:“NoCopyable ::运算符=”:不能访问类中声明私有成员“NoCopyable”

所以,我稍微修改代码使用替代的std ::交换功能我的版本交换功能,这里是代码:

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); 
} 

代码编译,并给出正确的结果。但是我不完全确定,我记得萨特的文章建议你避免玩物体的生活时间。这篇文章只是通过玩火来警告你,却没有给你任何真正的理由。如果T1或T2的拷贝构造函数可以抛出,我可以在异常安全中看到问题。但是,如果允许赋值运算符抛出,则标准版本中存在相同的问题。

在此问题上,你可以看到在这个版本中交换的任何可能的缺点?

干杯

+0

明确的析构函数调用看起来前途未卜恕我直言 – 2011-05-27 16:30:55

+1

你为什么要交换使用两种不同类型很少用到......?如果他们不同,使用一个对象的位置构造函数与另一个的地址将反正是非常糟糕的... – 6502 2011-05-27 16:30:58

+0

@良好的观点,它应该只是一个模板参数 – 2011-05-27 16:34:37

回答

6

不同之处在于,当赋值运算符失败时,仍然有相同数量的对象。

如果您销毁一个对象并且无法创建新对象,则会丢失一个对象!如果它是容器的一部分,容器的状态可能也是无效的。

3

这可能会让代码的未来维护者感到困惑。

8

二话不说,如果一个类没有赋值运算符,它的设计者可能没有打算将它交换。如果他们这样做了,他们可能也会禁用拷贝构造,所以你的新交换功能仍然无法工作。

至于你的说法,标准库容器不需要分配 - 这是真的,只要你不想真正做任何与他们有用。这段代码是为你编译的吗?我想它不会。

+0

+1。好答案。非常精确地陈述! – Nawaz 2011-05-27 16:37:07

+0

@Neil Butterworth如果对象的复制构造函数被禁用,则该对象不能与stl容器一起使用,所以没有太多的东西需要排序。 – 2011-05-27 16:40:26

+0

@Alessandro所以你正在处理的对象不能分配,但可以复制?根据我的经验,这种情况非常罕见。你的问题是关于swap()的。 – 2011-05-27 16:43:08

4

你需要一个拷贝构造函数,而不是一个赋值操作符,但两者是足够相似,至少在一般情况下,您将有两个或你有没有。 IOW,我认为这通常不会成就很多。

我倒是类是正确的旁边异或交换技巧:有趣,但一般没用。

相关问题