簡體   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