超载运算符中的分段错误=

时间:2010-01-03 22:16:08

标签: c++ segmentation-fault overloading

我在为一个FeatureRandomCounts类重载赋值运算符时遇到了一个seg错误,该类具有_rects作为其指针成员指向FeatureCount和大小rhs._dim的数组,并且其他日期成员是非指针:

FeatureRandomCounts &  FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)  
{  
  if (_rects) delete [] _rects;  

  *this = rhs;  // segment fault

  _rects = new FeatureCount [rhs._dim];  
  for (int i = 0; i < rhs._dim; i++)  
  {  
    _rects[i]=rhs._rects[i];  
  }  

  return *this;    
}

有人有一些线索吗?谢谢和问候!

4 个答案:

答案 0 :(得分:14)

*this = rhs;

调用operator =(),这是你正在编写的函数。提示无限递归,堆栈溢出,崩溃。

另外,如果你使用std :: vector而不是C风格的数组,你可能根本不需要实现operator =()。

答案 1 :(得分:7)

如上所述,你有无限的递归;但是,除此之外,这是实现op =:

的一种万无一失的方法
struct T {
  T(T const& other);
  T& operator=(T copy) {
    swap(*this, copy);
    return *this;
  }
  friend void swap(T& a, T& b);
};

编写正确的副本ctor和swap,并为您处理异常安全和所有边缘情况!

copy 参数通过值传递然后更改。当 copy 被销毁时,将处理当前实例必须销毁的所有资源。这遵循current recommendations并干净地处理self-assignment


#include <algorithm>
#include <iostream>

struct ConcreteExample {
  int* p;
  std::string s;

  ConcreteExample(int n, char const* s) : p(new int(n)), s(s) {}
  ConcreteExample(ConcreteExample const& other)
  : p(new int(*other.p)), s(other.s) {}
  ~ConcreteExample() { delete p; }

  ConcreteExample& operator=(ConcreteExample copy) {
    swap(*this, copy);
    return *this;
  }

  friend void swap(ConcreteExample& a, ConcreteExample& b) {
    using std::swap;
    //using boost::swap; // if available
    swap(a.p, b.p); // uses ADL (when p has a different type), the whole reason
    swap(a.s, b.s); // this 'method' is not really a member (so it can be used
                    // the same way)
  }
};

int main() {
  ConcreteExample a (3, "a"), b (5, "b");
  std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
  a = b;
  std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
  return 0;
}

请注意,它适用于手动管理的成员( p )或RAII / SBRM样式的成员( s )。

答案 2 :(得分:4)

 *this = rhs;  // segment fault

这绝对是的方式。您以递归方式调用=,而不是调用内置赋值运算符。逐个分配变量。不要偷懒。

答案 3 :(得分:3)

以下一行:

  *this = rhs;  // segment fault

将以递归方式调用operator=()函数,导致堆栈溢出。

您应该将其替换为各个成员字段的直接分配。

As Neil said,使用类似std::vector<>之类的内容可以消除代码中的大部分责任。如果由于某种原因您不能或不想使用std::vector<>,您可能还需要考虑为您的赋值运算符使用'swap idiom'。这将使函数异常安全(如果FeatureCount数组的内存分配失败并抛出异常,则分配给的原始对象将保持不变)。如下所示:

void FeatureRandomCounts::swap( FeatureRandomCounts& other)
{
    FeatureCount* tmp_rects = other._rects;
    int tmp_dim             = other._dim;    // or whatever type _dim is

    // similarly for other members of FeatureRandomCounts...

    // now copy the other contents to 
    this->_rects = other._rects;
    this->_dim   = other._dim;

    // assign other members of rhs to lhs

    other._rects = tmp_rects;
    other._dim   = tmp_dim;

    // etc.

    return;
}

现在,您的作业可能如下所示:

FeatureRandomCounts &  FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)  
{  
    FeatureRandomCounts tmp( rhs);  // make a copy

    tmp.swap( *this);               // swap the contents of the copy and *this

    return *this;
                                    // the contents of tmp (which has the old 
                                    //  stuff that was in *this) gets destructed
}

请注意,您需要一个合适的复制构造函数才能使用此工具,但鉴于Big 3 rule,您需要一个合适的复制文件。