求各位大佬幫助都哪有問題
參考的使用-函式名稱的參考
float t;
void main(){
float a=f1(5); float & b=f1(5);
float c=f2(5); float & d=f2(5);
float e=f3(5); float & f=f3(5);
float g=f4(5); float & h=f4(5);
}
float f1(float r)
{
return(3.14*r*r);}
float &f2(float r)
{
return(3.14*r*r);}
float &f3(float r)
{
float f; f=3.14*r*r; return(f);}
float &f4(float r)
{
t=3.14*r*r; return(t);}
uj5u.com熱心網友回復:
回傳區域變數的參考,是錯誤的,因為區域變數是在堆疊中,隨著函式的結束,堆疊中的資料會被清除。uj5u.com熱心網友回復:
uj5u.com熱心網友回復:
原則上不要參考堆疊記憶體,因為堆疊用完就釋放了,釋放掉的堆疊記憶體屬于垃圾記憶體。但是發現有一種情況可以例外,那就是物件(class的instance),貌似有的編譯器加入了記憶體逃逸分析
比如
class A {
public:
A(int n):n(n) {printf("create...%p, %d\n", this, n);}
~A(){printf("delete...%p, %d\n", this, n);}
int n;
};
struct B {
int n;
};
A getA() {
A a(1);
printf("in getA: %p, %d\n", &a, a.n);
return a;
}
void noReturnA() {
A a(2);
printf("in noReturnA: %p, %d\n", &a, a.n);
}
B getB() {
B b{3};
printf("in getB: %p, %d\n", &b, b.n);
return b;
}
void noReturnB() {
B b{4};
printf("in noReturnB: %p, %d\n", &b, b.n);
}
int main(int argc, const char * argv[]) {
A a = getA();
printf("out getA: %p, %d\n", &a, a.n); //getA函式內的區域變數a的記憶體地址和main函式的區域變數a的地址一樣
B b = getB(); //結構體好像沒有這樣的優化
printf("out getB: %p, %d\n", &b, b.n);
noReturnA();
noReturnB();
return 0;
}我的機器上運行的結果
create...0x7ffeefbff538, 1
in getA: 0x7ffeefbff538, 1
out getA: 0x7ffeefbff538, 1
in getB: 0x7ffeefbff4f8, 3
out getB: 0x7ffeefbff528, 3
create...0x7ffeefbff4f8, 2
in noReturnA: 0x7ffeefbff4f8, 2
delete...0x7ffeefbff4f8, 2
in noReturnB: 0x7ffeefbff4f8, 4
delete...0x7ffeefbff538, 1
uj5u.com熱心網友回復:
你這里好像么有回傳區域變數的參考吧
uj5u.com熱心網友回復:
看getA和getB,都回傳區域變數,但getA變數的記憶體地址和main的區域變數的地址一樣,也就是getA的區域變數系結的是main的a區域變數,但是getB不會。區別就是一個是物件,一個是結構體,也就是說結構體回傳時發生了復制(堆疊變數被釋放),而物件按理應該也發生了復制(但我這邊的情況是getA堆疊的物件沒有發生delete,而是直接系結main函式的區域變數),估計是編譯器自動生成了類的拷貝函式做什么手腳。但好像如果是自己加入拷貝函式的話,情況就會不一樣。
uj5u.com熱心網友回復:
那個不是參考哦uj5u.com熱心網友回復:
你的理解好像出了問題。uj5u.com熱心網友回復:
你的理解好像出了問題。
我的理解應該沒問題
也就是
A getA2(A *&p) {
A a(1);
p = &a; //按理p指向是堆疊記憶體地址,出了函式p成了也指標
int n = 1;
printf("in getA: %p, %d, %p\n", &a, a.n, &n);
return a;
}
但實際上
main函式
A *p;
A a = getA2(p); //p實際上不是也指標,而是指向了main的a
printf("out getA: %p, %d, %p\n", &a, a.n, p);
uj5u.com熱心網友回復:
A getA() {A a(1);
printf("in getA: %p, %d\n", &a, a.n);
return a;
}
B getB() {
B b{3};
printf("in getB: %p, %d\n", &b, b.n);
return b;
}
我不知道我是不是誤會你的意思,這兩個函式你是不是認為回傳了區域變數的參考??
uj5u.com熱心網友回復:
你的理解好像出了問題。
我的理解應該沒問題
也就是
A getA2(A *&p) {
A a(1);
p = &a; //按理p指向是堆疊記憶體地址,出了函式p成了也指標
int n = 1;
printf("in getA: %p, %d, %p\n", &a, a.n, &n);
return a;
}
但實際上
main函式
A *p;
A a = getA2(p); //p實際上不是也指標,而是指向了main的a
printf("out getA: %p, %d, %p\n", &a, a.n, p);
uj5u.com熱心網友回復:
請看上邊的回復????
getA和getB不是回傳參考,但我想表達的是區域變數的記憶體地址有所不同
就好像getA2,p是參考指標(為了傳入傳出,也相當于回傳值了),p按理是指向getA2區域變數a的地址吧,但getA2結束后p不是野指標,而是指向main函式的a,也就是p傳出getA2堆疊的地址沒問題(實際上該記憶體地址是main的)
如果改成
A getA2(int *&p) {
A a(1);
//p = &a.n; //如果是這里,p不是野指標
int n = 1;
p = &n; //這樣的話,出了getA3,p就是野指標
printf("in getA: %p, %d, %p\n", &a, a.n, &n);
return a;
}
main函式
int *p;
A a = getA3(p); //出了getA3,p就是野指標(但如果p指向getA3的a的n,就不是野指標)
printf("out getA: %p, %d, %p\n", &a, a.n, p);
uj5u.com熱心網友回復:
請重新組織一下語言,我沒看明白你要表達什么?一會兒getA2,一會兒getA3?讓人摸不到頭腦?uj5u.com熱心網友回復:
請重新組織一下語言,我沒看明白你要表達什么?一會兒getA2,一會兒getA3?讓人摸不到頭腦?uj5u.com熱心網友回復:
A getA2(A *&p),A getA3(int *&p)是新函式,是在getA的基礎上傳入一個參考指標,指標指向堆疊內變數的地址。說白了就是想表達,出了getA,getA2,getA3函式,它們的堆疊內的區域變數a并沒有消亡,也就是說該堆疊內區域變數a生命周期在函式堆疊外
uj5u.com熱心網友回復:
而noReturnA函式的區域變數a的生命周期就在noReturnA函式堆疊里,出了函式堆疊就被析構釋放了uj5u.com熱心網友回復:
哦,我說我怎么蒙蔽了,原來你說的是復制消除啊,這貼子在說回傳參考,而參考不會有復制消除,因為回傳參考不會產生復制。
你那個屬于不確定行為。有的編譯器會對A a=getA() 產生復制消除,有的不會。
uj5u.com熱心網友回復:
而noReturnA函式的區域變數a的生命周期就在noReturnA函式堆疊里,出了函式堆疊就被析構釋放了
#include <iostream>https://zh.cppreference.com/w/cpp/language/copy_elision
#include <vector>
struct Noisy {
Noisy() { std::cout << "constructed\n"; }
Noisy(const Noisy&) { std::cout << "copy-constructed\n"; }
Noisy(Noisy&&) { std::cout << "move-constructed\n"; }
~Noisy() { std::cout << "destructed\n"; }
};
std::vector<Noisy> f() {
std::vector<Noisy> v = std::vector<Noisy>(3); // 從臨時量 (C++17 前)
// 從純右值 (C++17 起)
// 初始化 v 中的復制消除
return v; // 從 v 到結果物件的 NRVO(C++17 中仍不保證)
} // 若禁用優化,則呼叫移動建構式
void g(std::vector<Noisy> arg) {
std::cout << "arg.size() = " << arg.size() << '\n';
}
int main() {
std::vector<Noisy> v = f(); // 從 f() 回傳的臨時量 (C++17 前)
// 從純右值 f() (C++17 起)
// 初始化 v 中的復制消除
g(f()); // 從 f() 回傳的臨時量 (C++17 前)
// 從純右值 f() (C++17 起)
// 初始化 g() 的形參中的復制消除
}
uj5u.com熱心網友回復:
哦,我說我怎么蒙蔽了,原來你說的是復制消除啊,
這貼子在說回傳參考,而參考不會有復制消除,因為回傳參考不會產生復制。
你那個屬于不確定行為。有的編譯器會對A a=getA() 產生復制消除,有的不會。
原來如此,我還以為是記憶體逃逸
uj5u.com熱心網友回復:
哦,我說我怎么蒙蔽了,原來你說的是復制消除啊,
這貼子在說回傳參考,而參考不會有復制消除,因為回傳參考不會產生復制。
你那個屬于不確定行為。有的編譯器會對A a=getA() 產生復制消除,有的不會。
原來如此,我還以為是記憶體逃逸
不是逃逸,復制消除其實是通過把外層變數的地址傳進函式,在函式中直接在那段記憶體上初始化,而做到的
uj5u.com熱心網友回復:
這是個啥?有點沒看懂uj5u.com熱心網友回復:
https://blog.csdn.net/dgyshy/article/details/105328279請復制這段鏈接,有詳細講解,望采納!
uj5u.com熱心網友回復:
可以用全域變數轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/91648.html
標籤:C++ 語言
