C ++返回临时对象的问题

时间:2016-02-27 04:34:33

标签: c++

大家好我在C ++工作了大约一个月,所以如果这个问题太过琐碎,请原谅。

#include <iostream>
using namespace std;

class Point {
    int x,y;

public:
    Point(int x_val = 0,int y_val = 0) :x(x_val),y(y_val) { }
    Point(Point& copy) : x(copy.x), y(copy.y) { }

    void showLocation() const { cout << "[" << x << "," << y << "]" << endl; }
    friend Point operator+(const Point& p1, const Point& p2);
    friend Point operator-(const Point& p1, const Point& p2);

    Point operator-(Point& p2) {                    // (1)
        Point(x-p2.x, y-p2.y).showLocation();
        return Point(x-p2.x, y-p2.y);
    }
};

Point operator+(const Point& p1, const Point& p2) { // (2)
    Point pos(p1.x+p2.x, p1.y+p2.y);
    return pos;
}

Point operator-(const Point& p1, const Point& p2) { // (3)
    return Point(p1.x-p2.x, p1.y-p2.y);
}

int main() {
    Point p1(3,4);
    Point p2(2,5);

    (p1+p2).showLocation();
    //(p1-p2).showLocation();
    operator-(p1,p2);
}

所以这是一个用于练习运算符重载的简单代码 - 我只是创建了一个点并重载了+和 - 运算符,它们都是类的成员和全局函数。

然而,当我编译这段代码时,我发现虽然(2)有效,但(1)和(3)都会继续显示我无法理解的错误:

  

q1.cpp:17:10:错误:没有用于初始化的匹配构造函数   &#39;点&#39;                   返回点(x-p2.x,y-p2.y);                          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   注意:候选构造函数不可行:没有已知的转换来自&#39; Point&#39;到&#39; int&#39;第一个参数

据我所知,(1)和(3)都应该返回一个临时的Point对象,根据谷歌的搜索,它应该等同于case(2)。

此外,错误陈述使我更加困惑 - 我无法看到在提到的表达式中发生任何转换是有问题的。

Point(x-p2.x, y-p2.y).showLocation();

这很好用,情况(2)也可以,所以我想这不是语法问题。除了关于返回临时对象(没有命名)的问题的可能性之外,我无法看到任何问题。

谢谢!

3 个答案:

答案 0 :(得分:1)

您只需删除复制构造函数即可解决此问题。它没有任何用处。或者,您可以根据默认签名在签名中使用func setupActivityView() { let screen = UIScreen.mainScreen().bounds let view = UIView(frame: CGRectMake(0.0, self.navbar.frame.height, screen.width, UIScreen.mainScreen().bounds.height-self.navbar.frame.height)) view.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.80) //view.hidden = true self.activityView = view self.view.addSubview(view) let spinner = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge) spinner.startAnimating() spinner.hidesWhenStopped = true self.spinner = spinner /*POINT:1*/ spinner.center = view.center /*POINT:2*/ spinner.frame.size = CGSizeMake(37.0, 37.0) /*POINT:3*/ //spinner.frame = CGRectMake((view.frame.width/2) - 18.5, (view.frame.height/2) - 18.5, 37.0, 37.0) view.addSubview(spinner) } 来修复复制构造函数。

const

如果没有Point(Point const & copy) : x(copy.x), y(copy.y) { } ,则复制构造函数不能与临时实例一起用作输入。

资源:

答案 1 :(得分:0)

此:

Point(Point& copy) : x(copy.x), y(copy.y) { }

是技术上有效的复制构造函数,但它限制了可能的实际参数。

临时或const对象不能绑定到Point&形式参数,因为这是对非const的引用,这将允许修改实际参数。

相反,你可以写

Point( Point const& other ): x( other.x ), y( other.y ) {}

我还纠正了误导性的争论命名。

但是更容易,对于这门课你可以做到

Point( Point const& other ) = default;

绝对最简单,只是根本不要定义复制构造函数,让编译器为你做。

同样,为了获得最大的可用性,您应该更改

Point operator-(Point& p2) {                   // (1)

Point operator-(Point const& p2) const {       // (1)

参数的const表示现在可以使用const或临时(rvalue)参数调用它。

成员函数本身的const,即最后const,意味着可以在const对象上调用它。这里的规则有点微妙。与参数的限制相反,没有const它就可以在临时对象上调用(即通过rvalue-expression)。

一般建议:

  • 在任何可以使用的地方随意撒上const

  • 让编译器生成复制操作,除非您负责复制

  • 优先使用复制安全的类型的数据成员,例如内置类型,智能指针和标准库集合。

答案 2 :(得分:0)

错误的原因(在您的情况下为(1))是

Point operator-(Point& p2) {                    // (1)
    Point(x-p2.x, y-p2.y).showLocation();
    return Point(x-p2.x, y-p2.y);
}

Point(x-p2.x, y - p2.y)生成一个临时对象。返回(语义上)需要创建临时副本,这需要一个接受const参数的拷贝构造函数。您的复制构造函数不接受const参数。

解决方案是修改你的拷贝构造函数以接受const参数,或者完全删除它(因为编译器会自动生成一个适合你的拷贝构造函数)。在C ++ 11中,如果需要,使用Point(const Point &) = default;来强制编译器生成正确的拷贝构造函数。

注意:该标准要求编译器强制要求正确的复制构造函数,即使临时优化已经存在。这有助于提高代码的可移植性,使编译器不会优化临时性。

您的代码的另一个问题是您有operator-()的两种变体。

您的案例(1)和(3)不相同。第一个生成operator-()的成员函数形式(它接受一个参数,因为存在隐含的this),第二个是非成员形式,它接受两个参数。

当它看到p1-p2这样的表达式(其中p1p2都属于Point类型)时,operator-()的两个版本都同样出色候选人。编译器会抱怨歧义,因为它没有理由偏爱另一个。所以声明

(p1-p2).showLocation();

不会编译。我认为你已经因为这个原因对它进行了评论。

解决方法是使用operator-()的一种形式或另一种形式。不是一次两个。