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

发布于 2024-08-16 20:43:13 字数 489 浏览 3 评论 0原文

我刚刚在重载类 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;    
}

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

I just got a seg fault in overloading the assignment operator for a class FeatureRandomCounts, which has _rects as its pointer member pointing to an array of FeatureCount and size rhs._dim, and whose other date members are non-pointers:

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

Does someone have some clue? Thanks and regards!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我家小可爱 2024-08-23 20:43:13
*this = rhs;

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

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

*this = rhs;

calls operator=(), which is the function you are writing. Cue infinite recursion, stack overflow, crash.

Also, if you used a std::vector rather than a C-style array, you probably would not need to implement operator=() at all.

剑心龙吟 2024-08-23 20:43:13

如前所述,您有无限递归;然而,除此之外,这里有一个万无一失的方法来实现 op=:

struct T {
  T(T const& other);
  T& operator=(T copy) {
    swap(*this, copy);
    return *this;
  }
  friend void swap(T& a, T& b);
};

编写正确的复制构造函数和交换,并且异常安全和所有边缘情况都会为您处理!

copy 参数按值传递,然后进行更改。当copy被销毁时,当前实例必须销毁的任何资源都会被处理。这遵循当前建议并处理干净地自我分配


#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)。

As mentioned, you have infinite recursion; however, to add to that, here's a foolproof way to implement op=:

struct T {
  T(T const& other);
  T& operator=(T copy) {
    swap(*this, copy);
    return *this;
  }
  friend void swap(T& a, T& b);
};

Write a correct copy ctor and swap, and exception safety and all edge cases are handled for you!

The copy parameter is passed by value and then changed. Any resources which the current instance must destroy are handled when copy is destroyed. This follows current recommendations and handles self-assignment cleanly.


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

Notice it works with either manually managed members (p) or RAII/SBRM-style members (s).

捂风挽笑 2024-08-23 20:43:13
 *this = rhs;  // segment fault

这绝对不是这样做的方法。您递归地调用 =,而不是调用内置的赋值运算符。将变量一一赋值。不要偷懒。

 *this = rhs;  // segment fault

This is definitively not the way to do it. You call = recursively, not calling the built in assignment operator. Assign variables one by one. Don't be lazy.

辞取 2024-08-23 20:43:13

以下行:

  *this = rhs;  // segment fault

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

您可能应该用各种成员字段的直接分配来替换它。

正如尼尔所说,使用类似 std::vector< ;> 将从您的代码中消除大部分责任。如果出于某种原因您不能或不想使用 std::vector,您可能还需要考虑对赋值运算符使用“交换习惯用法”。这将使函数异常安全(如果为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
}

请注意,您需要一个适当的复制构造函数才能使其工作,但考虑到 三大规则 你已经需要一个合适的复制者了。

The following line:

  *this = rhs;  // segment fault

will recursively call your operator=() function resulting in a stack overflow.

You should probably replace it with straight-forward assignments of the various member fields.

As Neil said, using something like std::vector<> will remove much of the responsibility away from your code. If for whatever reason you can't or don't want to use std::vector<>, you might also want to consider using the 'swap idiom' for your assignment operator. This will make the function exception safe (if the allocation of the memory for FeatureCount array fails and throws an exception, the original object that's being assigned to will be left unchanged). Something like the following:

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

Now your assignment can look like:

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
}

Note that you need a proper copy constructor for this to work, but given the Big 3 rule you already need a proper copy ctor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文