繁体   English   中英

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

[英]C++ an issue with returning a temporary object

您好,我用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:错误:没有匹配的构造函数来初始化'Point'返回Point(x-p2.x,y-p2.y); ^ ~~~~~~~~~~~~~~~~~~~~ q1.cpp:8:2:注意:候选构造函数不可行:第一个参数从'Point'到'int'的未知转换

据我了解,(1)和(3)均应返回一个临时Point对象,根据Google搜索,该对象应与情况(2)等效。

另外,错误语句使我更加困惑-我看不到在表达式中发生的任何转换都是有问题的。

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

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

谢谢!

您可以通过简单地删除复制构造函数来解决此问题。 它没有任何用处。 或者,您可以根据默认签名在签名中使用const来修复副本构造const

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

如果没有const ,则复制构造函数不能与临时实例一起用作输入。

资源:

这个:

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或临时(右值)参数调用它。

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


一般建议:

  • 在几乎可以使用的任何地方自由地散布const

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

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

错误的原因(在您的情况下为(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参数。

解决方案是修改您的副本构造函数以接受const参数,或者将其彻底删除(因为编译器会自动生成一个对您而言正确工作的副本构造函数)。 在C ++ 11中,使用Point(const Point &) = default; 如果需要,可以强制编译器生成正确的副本构造函数。

注意:该标准要求编译器强制执行对正确的副本构造函数的需求,即使临时文件已被优化为不存在也是如此。 这有助于提高代码对未优化临时文件的编译器的可移植性。

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

您的情况(1)和(3)不相等。 第一个生成operator-()的成员函数形式(接受一个参数,因为有一个隐含this ),第二个生成的非成员形式接受两个参数。

当它看到一个类似p1-p2的表达式(其中p1p2都是Point类型)时,该operator-()两个版本都是不错的候选者。 编译器会抱怨模棱两可,因为没有理由比另一个更偏爱一个。 所以一个声明

(p1-p2).showLocation();

将无法编译。 我认为您是出于这个原因将其注释掉了。

解决方案是使用operator-()一种形式或另一种形式。 不能一次全部。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM