【问题标题】:Copy constructor invokes an infinite loop复制构造函数调用无限循环
【发布时间】:2010-01-28 08:33:46
【问题描述】:

我将一个值作为引用传递给复制构造函数,但正在调用一个无限循环。

这是我的课:

class Vector2f{
private:
    GLfloat x;
    GLfloat y;

public:
    Vector2f();
    Vector2f(const GLfloat _x, const GLfloat _y);
    Vector2f(const Vector2f &_vector);

    ~Vector2f();
};

这里是方法的实现:

Vector2f::Vector2f():
        x( 0.0f ),
        y( 0.0f )
{
    DebugLog("Vector2f constructor");
}

Vector2f::Vector2f(const GLfloat _x, const GLfloat _y):
        x( _x ),
        y( _y )
{
    DebugLog("Vector2f constructor(%f, %f)", _x, _y);
}


Vector2f::Vector2f(const Vector2f &_vector):
        x( _vector.getX() ),
        y( _vector.getY() )
{
    DebugLog("Vector2f copy constructor");
}

Vector2f::~Vector2f()
{

}

这是我访问课程的方式:

Vector2f tempVector1 = Vector2f(0.0f, 0.0f);
DebugLog("tempVector1 initialized");

Vector2f tempVector2;
tempVector2 = Vector2f(0.0f, 0.0f);
DebugLog("tempVector2 initialized");

我得到的结果是:

Vector2f constructor(0.000000, 0.000000)
tempVector1 initialized
Vector2f constructor
Vector2f constructor(0.000000, 0.000000)
Vector2f copy constructor
Vector2f copy constructor
Vector2f copy constructor
...

尝试初始化先前创建的对象时会发生无限循环。 如果我尝试将 tempVector1 复制到 tempVector 2 中,也会发生无限循环:

Vector2f tempVector2;
tempVector2 = Vector2f(tempVector1);

为什么会发生,如何防止它进入无限循环?

提前谢谢你。

【问题讨论】:

  • 你没有忘记& 中的Vector2f(const Vector2f &_vector); 吗?
  • @Kirill。真的。它不编译。找不到getX 和getY。

标签: c++ infinite-loop copy-constructor


【解决方案1】:

这一行:

tempVector2 = Vector2f(tempVector1);

将调用 operator=,而不是复制构造函数。您是否定义了一个正在做一些古怪事情的 operator=?

此外,您的代码在 Linux 上的 g++ 4.3.2 和 Mac 上的 g++ 4.2.1 都可以正常工作(在我定义 getX、getY、将 DebugLog 转换为 printf 并使用 float 而不是 GLfloat 之后)。

【讨论】:

  • 我也会这么说,有些代码是不可见的。从上面显示的代码,我看不出有什么问题。
  • 谢谢 问题不在复制构造函数,而在赋值运算符。
  • 不完全准确。首先,由于显式转换(将调用复制构造函数),它将调用两者。其次,在初始化operator =的参数时,它可以根据需要多次调用复制构造函数。
【解决方案2】:

我认为问题出在您的赋值运算符上。 operator= 长什么样子?

似乎 operator= 以某种方式称他为 self。代码 sn-p 是否可能取自 operator= 本身的主体?

如果是,那么解决方案是更改代码(在 operator= 内),使其使用复制 ctor。规范形式如下:

Vector2f temp = Vector2f(arg);
swap(*this, temp)   // You need to implement a swap method
return *this; 

(有关详细信息,请参阅 Herb Sutter 的 Exceptional C++)

【讨论】:

  • 嗯。这个答案重复了 R Samuel Klatchko 的答案。接受重复的答案?
【解决方案3】:

在第二种情况下,您执行的是分配,而不是构造。您尚未定义自己的复制赋值运算符版本,这意味着编译器将为您提供一个。编译器提供的复制赋值运算符将被隐式声明为

Vector2f& operator =(const Vector2f& rhs);

请注意,此运算符的唯一参数具有对 const 的引用类型。

在您的代码中,您坚持在赋值的右侧提供Vector2f 类型的临时右值 对象。

tempVector2 = Vector2f(0.0f, 0.0f);

这意味着operator = 的引用参数被初始化为一个类类型的临时右值。根据语言规范(8.5.3/5),编译器可以在实际附加引用之前复制该临时对象任意多次。最终它必须停止复制并最终呼叫操作员。通常编译器不会因复制而疯狂(其中大多数根本不复制),但是在您的情况下,这似乎是问题所在。出于某种原因,您的编译器被锁定在无限复制循环中,永远不会停止它。我不知道这是什么原因造成的。可能是编译器中的错误。

请注意,即使在

tempVector2 = Vector2f(tempVector1);  

您仍然以临时右值的形式提供右侧。右值是显式转换为Vector2f 的结果,您出于某种原因放在那里。我不知道你为什么这样做。如果问题确实出在编译器中(而不是在您没有向我们展示的代码中),我敢肯定,如果您只是这样做

tempVector2 = tempVector1;  

任务将顺利进行。如果它被证明是编译器中的错误,这实际上是您可以解决该问题的方法:停止使用临时变量作为复制构造函数和复制赋值运算符的参数。

【讨论】:

    【解决方案4】:

    在 IDE 下运行它。当它在循环中时,按“暂停”按钮。您将确切地看到问题所在。 Here's why.

    【讨论】:

      猜你喜欢
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-14
      • 2018-10-17
      • 2014-03-03
      • 1970-01-01
      相关资源
      最近更新 更多