i++,++i的討論引題
臨時對象都是右值
//臨時對象
//i++,右值,會產生一個臨時對象,
//如何保存這個臨時對象
int i = 0;
int&& saveI = i++;//這樣寫的話,這個臨時變量就會一直保存到程序結束,saveI和i之間沒有什麼關係
爲什麼減少臨時變量能提升系統效率呢?
要知道臨時對象
是存貯在棧
中的,如果寫代碼的時候能減少臨時變量的產生,將會提升系統的效率
一:產生臨時對象的情況和解決方案
1、以傳值的方式給函數傳遞參數,這個用得太多了,所以就不舉例說明了
2、類型轉換生成的臨時對象 / 隱式類型轉換以保證函數調用成功
2.1 類型轉換生成的臨時對象
class classA
{
public:
int val1;
int val2;
public:
classA(int a = 1, int b = 2);
classA(const classA& obj);
virtual ~classA();
classA& operator=(const classA& obj);
};
classA::classA(int a, int b) :val1(a), val2(b)
{
cout << "調用了構造函數" << endl;
cout << "val1 = " << val1 << endl;
cout << "val2 = " << val2 << endl;
}
classA::classA(const classA& obj)
{
cout << "調用了拷貝函數" << endl;
val1 = obj.val1;
val2 = obj.val2;
}
classA::~classA()
{
cout << "調用了析構函數" << endl;
}
classA& classA::operator=(const classA& obj)
{
cout << "調用了賦值運算符" << endl;
val1 = obj.val1;
val2 = obj.val2;
return *this;
}
int main()
{
classA myClassA;
myClassA = 1000;//這一步用的是賦值運算符
}
運行結果:
可以看出,就這一個“=”號就做了三件事情
- 1、執行了構造函數,創建了一個臨時變量
- 2、執行了賦值運算符,將值傳遞給對象
- 3、執行了析構函數
這樣系統白白多執行了三個步驟
我們如何改進呢?
最好初始化的時候就賦值,這樣就不會生成臨時變量
classA myClassA = 1000;
執行效果如下
2.2 隱式類型轉換以保證函數調用成功
//可以看到,傳遞進來的參數是char數組,而接收卻用的是const string&
//這裏系統就會直接進行隱式類型轉換
//那麼可不可以用string& 來接收呢?
//那肯定是不行的,正面理解比較困難,我們反着理解
//如果你用了string& sourceStr 來接收,系統會認爲你有權限去改變sourceStr
//但是這個string是系統給你構造的臨時變量,不會造成原先char數組的改變,系統爲了防止你無意中犯下這個錯誤
//編譯的時候就會告訴你出錯
//系統會爲const string& sourceStr構造臨時變量
//但是不會爲string& sourceStr構造臨時變量
int testMethod1(const string& sourceStr, char x)
{
const char* p = sourceStr.c_str();
int count = 0;
//todo
return count;
}
int main()
{
char myCharArray[100] = "I Love You";
int result = testMethod1(myCharArray, 'o');
cout << result << endl;
}
3、函數返回對象的時候
classA testMethod2(classA& obj)
{
classA myNewClassA;
myNewClassA.val1 = obj.val1;
myNewClassA.val2 = obj.val2;
return myNewClassA;
}
int main()
{
classA myClassB;
testMethod2(myClassB);
}
這裏return myNewClassA
的時候,也會創造一個臨時變量
執行效果如下:可以看出,我們只顯式聲明瞭兩個對象,可是卻調用了三次析構函數,一次拷貝構造函數,可以得出結論:
return myNewClassA
的時候,會創造一個臨時變量
那麼如何改進呢?
classA testMethod2(classA& obj)
{
return classA(obj.val1, obj.val2);//這樣就不會構造臨時對象了
}
int main()
{
classA myClassB;
//這裏直接接收返回的對象,會保存函數內部創建的對象
classA myNewClassB = testMethod2(myClassB);
}
執行效果如下:
二:類外運算符重載
class testclass
{
public:
testclass(int a = 0, int b = 0) :a(a), b(b) {};
public:
int a;
int b;
};
//這是經過優化過臨時變量的類外運算符重載
testclass operator+(testclass& class1, testclass& class2)
{
return testclass(class1.a + class2.a, class1.b + class2.b);
}
int main()
{
testclass class1(1, 2);
testclass class2(1, 2);
testclass class3 = class1 + class2;
cout << class3.a << endl;
cout << class3.b << endl;
return 0
}
運行結果如下: