簡體   English   中英

減少復制構造函數調用

[英]Reduce Copy Constructor Calls

以下代碼是我正在處理的項目中的一個最小示例。 主要問題是我想減少對復制構造函數的調用次數,但我不清楚這樣做的正確方法。

#include<iostream>

class MyClass
{
public:
    MyClass() {std::cout << "Default Constructor\n";}
    MyClass(const MyClass &input) {std::cout << "Copy Constructor\n";}
    MyClass & operator=(const MyClass &input) 
         {std::cout << "Assignment\n"; return *this;}
    MyClass & operator+=(const MyClass &input) {return *this;}
    friend MyClass operator+(MyClass lhs,const MyClass &);
};

MyClass operator+(MyClass lhs,const MyClass &rhs) 
    {lhs+=rhs;return lhs;}

int main()
{
    MyClass a,b,c;
    c=a+b;
    return 0;
}

當我運行代碼時,輸​​出是:

Default Constructor
Default Constructor
Default Constructor
Copy Constructor
Copy Constructor
Assignment
  • 三個默認構造函數在 a、b 和 c 的構造中被調用。

  • 這兩個復制構造函數在 operator+ 中的第一個參數和 operator+ 的返回值中被調用。

  • 賦值將 a+b 賦值給 c 的結果賦值。

主要問題:在我的應用程序中,復制構造函數很昂貴(它涉及內存分配)。 另一方面,分配相對便宜。 減少對復制構造函數的調用的正確方法是什么?

我考慮了一些解決方案,但沒有一個讓我高興:

  • 據我了解,從閱讀中可以看出,operator+ 不應該有第一個參數的引用,因為這有助於鏈接臨時變量。 因此,這種復制構造函數似乎是不可避免的。

  • 以下代碼明顯更快(由於沒有復制構造函數調用): c = a; c += b; c = a; c += b; 我可以使用這種格式編寫代碼,但這需要更精細的方法。 我希望編譯器比我自己做這些調整更聰明。

  • 我可以實現一個函數add(MyClass &,const MyClass &,const MyClass &); 但這失去了使用加法運算符的便利性(並且由於我使用的不同數據類型的數量而需要大量(無意識的)編碼)。

  • 我已經查看了這些問題,但在這種情況下我沒有看到任何可能提高性能的建議:

復制構造函數調用兩次復制構造函數調用兩次復制省略條件

對評論的回應:

  • 私有數據包括 MPFR's 和 MPFI's,構造函數包括該數據的初始化。 也許構造函數的不同實現是合適的,但我不確定。

  • 我考慮過移動構造函數,但有時我也需要復制副本分配。 cppreference看來,這些不能共存(或者至少當我一開始嘗試時出現錯誤)。 看來這應該是最好的選擇。

您正在通過副本傳遞lhs 這就是為什么你有額外的復制構造函數調用。 修改您的operator+

MyClass operator+(const MyClass &lhs, const MyClass &rhs)

為了盡量減少復制構造函數調用,我建議您定義移動構造函數並完美轉發您的運算符參數。 移動構造函數:

MyClass(MyClass &&input) {std::cout << "Move Constructor\n";}

完美轉發運營商:

template<typename T>
    friend MyClass operator+(T &&lhs,T &&rhs) {return std::forward<T>(lhs);}

通過正確的調用,您的運算符將涉及移動構造函數而不是復制構造函數。 例如,如果您添加來自函數的對象並立即存儲結果(例如MyClass c=a+b;而不是MyClass c;c=a+b; ),由於RVO,您可以保存復制構造函數。

假設您有一個返回MyClass實例的函數:

MyClass something() {return MyClass();}

如果添加函數返回值並立即存儲它們,例如:

MyClass c=something()+something();

那么就不會涉及復制構造函數。

在這里放了一系列示例其中我將const MyClass&參數與operator+並將完美轉發參數與operator- 您可以看到它在最后一個示例中有所不同,但在所有其他示例中沒有。 這就是為什么我說“用正確的電話”。 如果您必須操縱可以像這樣轉發的對象,則可能值得一試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM