g++編譯優化選項-fno-elide-constructors

1、考慮下面的代碼,請問輸出結果是什麼?

#include <stdio.h>

class A {
public:
	A(int val) {
		puts("A(int)");
		d = val;
	}
	A(A&& a) {
		puts("A(A&&)");
		d = a.d;
	}
	A(A& a) {
		puts("A(A&)");
		d = a.d;
	}
	~A() {}
private:
	int d;
};
A create_A(int val) {
	return A(val);
}
int main(void) {
	A a{create_A(5)};

	return 0;
}

如果你認爲應該輸出下面的結果,那就不用繼續往下看了。

$ g++ ./main.cpp
$ ./a.out
A(int)

2、對於上面的輸出結果,是不是或多或少有點出乎意料。從輸出結果來看,只調用了一次構造函數,而且 移動構造函數 和 拷貝構造函數 都沒有被調用。爲什麼會這樣?是因爲編譯器對返回值做了優化,何以見得?我們可以打印一下create_A()中臨時對象的地址,然後再打印一下main函數中對象a的地址,會發現他們是一樣的。

#include <stdio.h>

class A {
public:
	A(int val) {
		puts("A(int)");
		d = val;
	}
	A(A&& a) {
		puts("A(A&&)");
		d = a.d;
	}
	A(A& a) {
		puts("A(A&)");
		d = a.d;
	}
	~A() {}
private:
	int d;
};
A create_A(int val) {
	A a(val);
	printf("create_A()::&a = %p\n", &a);
	return a;
}
int main(void) {
	A a{create_A(5)};
	printf("main()::&a = %p\n", &a);

	return 0;
}

程序運行結果如下:

$ g++ ./main.cpp
$ ./a.out
A(int)
create_A()::&a = 0x7ffee7bd08f8
main()::&a = 0x7ffee7bd08f8

3、如果開啓了-fno-elide-constructors編譯選項,結果就更容易理解了

$ g++ -fno-elide-constructors main.cpp
$ ./a.out
A(int)
create_A()::&a = 0x7ffee73018b8
A(A&&)
A(A&&)
main()::&a = 0x7ffee73018f8

從輸出結果來看,拷貝構造函數被調用了兩次,一次是create_A()內部創建的對象返回後構造一個臨時對象產生的,另一次是在main函數中構造對象a產生的,同時,create_A()中對象a的地址與main函數中對象a的地址不相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章