关于混合使用智能指针和内置指针的自己的问题和自己的见解(问题搜集中)这个帖子有待解决的问题
下面很多例子用到process函數,process定義如下:
void process(shared_ptr<int> ptr){//使用ptr}//ptr離開作用域,被銷毀1.定義不當的?
#include <iostream> #include <string> #include <memory> using namespace std; int main() { shared_ptr<int> p(new int(123)); shared_ptr<int> p1(p); //下面定義可以通過編譯,但是不能使用use_count成員函數 //也可以解引用,結果是1,鬼知道是咋回事,所以給shared_ptr賦值的對象也是shard_ptr時候,別多轉換代碼,否則錯誤一大堆,還不能正常使用。 //后來又查書,下面的代碼是利用p構造一個新的shared_ptr賦值給p2,但是不能把臨時構造的在用來臨時構造,否則不能用use_count函數 shared_ptr<int> p2(shared_ptr<int>(p));//圓括號內直接放p就可以了。 cout << p.use_count() << endl; cout << p1.use_count() << endl; cout << p2.use_count() << endl;return 0; } ~ ~再看一個臨時構造的例子,我自己得到的結論是,若果用一個shared_ptr對象p1去臨時構造一個shared_ptr對象p2(p2 = shared_ptr<int>(p1)),p1可以正常使用,包括解引用,get()和use_count()成員,但是如果繼續用p2用相同方法構造一個p3,那么p3就不能正常使用了。解引用,get和use_count成員都會出錯的。?
#include <string> #include <iostream> #include <memory> using namespace std; void process(shared_ptr<int> ptr) {cout << "execute the program." << endl;cout << "print :" << *ptr << endl;cout << "delete ptr automatically.." << endl;cout << ptr.use_count() << endl;cout << ptr.get()<< endl;shared_ptr<int> p2(shared_ptr<int>(ptr));//下面的2語句就會出錯,也就是說,如果ptr是臨時構造的,然后再用ptr臨時構造,就會出問題,不能使用use_count和get這兩個成員函數,而且,解引用也會報錯。 //cout << p2.use_count() << endl;//cout << p2.get() << endl;cout << "p2 's value is:"<<*p2 << endl; }int main() { shared_ptr<int> p(new int(42)); cout << "p's get is:" << p.get() << endl; process(p); process(shared_ptr<int>(p));return 0; } ~ shared_ptr<int> p(new int(42)); shared_ptr<int> p2 = (shared_ptr<int>(p)); shared_ptr<int> p3 = shared_ptr<int>(p2); shared_ptr<int> p4(shared_ptr<int>(p3)); //用等號一般都是沒問題(例如前三行),但是如果是臨時構造出來的(第四行),使用p4就會出問題?
2.關于c++primer5th? 414頁一段代碼說是可以銷毀指針,結果自己實驗是不可以銷毀的。改成下面的是可以銷毀的,
#include <iostream> #include <string> #include <memory> using namespace std; int main() { shared_ptr<int> p(new int(42)); int *q = p.get(); { int * k = new int; k = q; delete k; } cout << *q << endl; cout << *p << endl; { auto p = new int(1234); auto sp = make_shared<int>();{shared_ptr<int> p1 = shared_ptr<int>(p);}上面這個代碼也可以釋放p1,p1釋放,p也就釋放了。
auto p = new int(1234); auto sp = make_shared<int>(1111);{shared_ptr<int> p1 = shared_ptr<int>(sp);}上面雖然是利用sp構造一個shared_ptr,但是p1也是指向sp的,最后在塊內(打括號內)引用計數是2
但是,如果按照下面的構造方式,就會報錯:
auto sp = make_shared<int>(1111);{shared_ptr<int> p1(shared_ptr<int>(sp));}大括號內,執行p1.get()和p1.use_count()都會報錯。解引用p1會得到1,而不是我們期望的1111.為什么?
所以,不能利用一個智能指針構造另一個智能指針。
修改如下,就可以,不調用構造函數,用=就可以:
auto sp = make_shared<int>(1111);{shared_ptr<int> p1 = shared_ptr<int>(sp);}3.用get()返回的指針構造一個臨時的shared_ptr(例如 p3 = shared_ptr<int>(get返回的指針)),那么這個p3(用get返回值構造出來的指針也會出問題)
#include <string> #include <iostream> #include <memory> using namespace std;int main() { shared_ptr<int> p(new int(42)); int *q = p.get();{ shared_ptr<int> k(shared_ptr<int>(q)); cout << k.use_count() << endl; //為啥這里會報錯? }//cout << *q << endl; return 0; } ~ ~ ~g++編譯器報錯如下:
r@r:~/coml/c++/12/12.1/12.1.3/ex$ g++ ex1.cc -o 123 ex1.cc: In function ‘int main()’: ex1.cc:14:11: error: request for member ‘use_count’ in ‘k’, which is of non-class type ‘std::shared_ptr<int>(std::shared_ptr<int>)’14 | cout << k.use_count() << endl;有時候會如下報錯,
free(): double free detected in tcache 2 Aborted (core dumped)綜上所述,get()返回值來構造一個shared_ptr大多數不會正確執行的。
再比如,process定義如下
void process(shared_ptr<int> ptr) { ... } shared_ptr<int> p(new int(42));那么我們執行
process(shared_ptr<int>(p.get()));會出什么問題?
首先,利用shared_ptr<int>(p)來夠早shared_ptr,那么p必須是動態指針,而不是普通指針,利用普通指針構造的對象將不會正確地構造處shared_ptr,這就是為什么不能利用get()返回值來初始化shared_ptr的原因所在。更不能給shared_ptr賦值。
正如c++primer5th,414頁有這么一句話:
其次,用get()返回值得到的shared_ptr不是一個正確的shared_ptr,將不會形成正確的動態對象共享,因為參數不正確參數不是一個動態內存指針,所以編譯器會利用shared_ptr<int>(p.get())新構造出來的指針和原來的指針p是兩個不同的對象(編譯器會認為p和新構造出來的對象是兩個不相干的shared_ptr,雖然它們相等),而非共享一個對象,所以p和ptr(新構造出來傳給ptr了)的是兩個不同的對象,兩個引用計數都是1。當process調用以后,ptr的引用計數是0,所管理的內存地址被釋放,而此內存就是p管理的。p稱為一個空懸指針的shared_ptr。
再次,再看一個get()構造shared_ptr的例子:
#include <iostream> #include <vector> #include <string> #include <memory> using namespace std; void process(std::shared_ptr<int> ptr) {std::cout << "inside the process function:" << ptr.use_count() << "\n"; }int main() {std::shared_ptr<int> p(new int(42));/*** @brief std::shared_ptr<int>(p.get()) construct a temporary shared_ptr* and copy it* to the parameter.However it is not a copy of p. As a result, at* end of this* main function p will free the memory that has been freed inside* process ().* That's why "double freed or corruption" was generated.*/process(std::shared_ptr<int>(p.get()));return 0; } ~ ~ ~上面代碼g++編譯器會報錯如下:
inside the process function:1 p 's use_count is: 1 free(): double free detected in tcache 2 Aborted (core dumped)double free tetected in tcache?
最后在看一個get()得到的普通指針例子:
#include <iostream> #include <vector> #include <string> #include <memory> using namespace std; void process(std::shared_ptr<int> ptr) {std::cout << "inside the process function:" << ptr.use_count() << "\n"; }int main() { auto sp = make_shared<int>(); auto p = sp.get(); delete p;return 0; } ~ ~ ~ double free or corruption (out) Aborted (core dumped)結論:get得到的指針不能delete,也就是說當delete p執行后,sp.use_count()仍然為1,但是已經被釋放。main()函數結束的時候,程序會遞減sp引用計數,sp引用計數會為0,那么此時sp指向的對象有一次被釋放,但是前面已經被釋放了,所以會報錯。自由空間被釋放2此會破壞自由空間。??也就是double free or corruption.....
4.
#include <string> #include <iostream> #include <memory> using namespace std;int main() { shared_ptr<int> p(new int(42)); int *q = p.get();{ //下面這句和shared_ptr<int> k(shared_ptr<int>(p));有啥區別,為啥如果下面這句對,本行這句錯? //自己猜測是,本行這句是用p臨時構造的,賦值給k,理論上臨時構造的也是賦值給k,k也是指向p的 //這個是構造和=(拷貝)當然不一樣,區別大,慢慢研究吧shared_ptr<int> k = shared_ptr<int>(p); cout << *k << endl; cout << k.use_count() << endl; } //cout << *q << endl; return 0; } ~ ~5.c++primer 5th,習題12.12
(a)是合法的,process需要一個shared_ptr參數,sp也是一個shared_ptr對象,完全可以的
并且在調用過程中,ptr的use_count()為2,值為0(值初始化)
(b)不合法,不能把普通指針,轉換為智能指針.g++編譯器,會報錯,如下:
could not convert ‘(operator new(4), (<statement>, ((int*)<anonymous>)))’ from ‘int*’ to ‘std::shared_ptr<int>’(c)不合法,不能把普通指針轉換為只能指針,g++編譯器會報錯如下:
error: could not convert ‘p’ from ‘int*’ to ‘std::shared_ptr<int>’(d)合法。但不好。調用結束后構建的臨時對象會被銷毀,所指向的內存會被釋放。
6.在看一個智能指針的錯誤使用
#include <iostream> #include <string> #include <memory> using namespace std; int main() { int *p = new int(1234); //我個人的理解是,shared_ptr<int>(p)是臨時構造的,傳遞給shared_ptr的構造函數后,那么構造函數用完后就把這個臨時變量釋放了,這個臨時變量和p1都是是指向原來p指向的對象的,所以p1構造完畢后p也就釋放掉了。也就是執行完構造函數后,p就成為空懸指針了,指向它的p1也沒有意義了。改正看綠色字體 shared_ptr<int> p1(shared_ptr<int>(p));//cout << p1.use_count() << endl; //cout << p1.get() << endl; cout << *p1 << endl; return 0; } ~ ~但是,如果執行玩p1的構造函數后,p會被釋放,為何main()函數return前還是可以繼續打印出p的指向的值(1234)?呢?
p1的值自從執行完shared_ptr<int> p1(shared_ptr<int>(p))后確實已經變成1了,而不是期望的1234
還有,如果改成下面的形式,會完全正確的。是不是因為shared_ptr<int>做構造函數參數,那么構造函數執行完畢,釋放內存了?
而如果是換成是new分配的就不會出現這問題,因為new分配的只要不delete就永久存在?所以得出結果,臨時構造出來的智能指針不能做函數參數....是嗎?
如果說是因為構造函數釋放了p,但是構造后為啥p還是可以解引用出原來的值的?如果說是沒有釋放,為何p1就已經被破壞了?這只能有一個解釋,那就是下面代碼構造處的p1是獨立于p的另一個備份。也就是shared_ptr<int>(p)是開辟了一個新的空間,
指向構造函數的參數的,但是構造完畢后,被釋放了。除此之外,我實在想不出其它可能了。
所以。要構造就用內置指針,
int *p = new int(1234); shared_ptr<int> p1(p);?下面這句是不對的。
shared_ptr<int> p1(shared_ptr<int>(p));?如果用shared_ptr,就用=復制
shared_ptr<int> p1 = shared_ptr<int>(p);運行結果是:1,而不是1234
而且p1.use_count()和p1.get()均會報錯,g++提示如下錯誤:
6.cc: In function ‘int main()’: 6.cc:10:12: error: request for member ‘use_count’ in ‘p1’, which is of non-class type ‘std::shared_ptr<int>(std::shared_ptr<int>)’10 | cout << p1.use_count() << endl;| ^~~~~~~~~ 6.cc:11:12: error: request for member ‘get’ in ‘p1’, which is of non-class type ‘std::shared_ptr<int>(std::shared_ptr<int>)’11 | cout << p1.get() << endl;| ^~~稍微總結下吧,當我們定義一個只能指針時候,例如
?
shared_ptr<int> p(q);這里q要么是一個new 分配的表達式,要么是一個shared_ptr指針(但不能是臨時用內置指針構造的shared_ptr),如果相用內置指針來構造一個臨時的shared_ptr傳遞傳遞給一個智能指針,只能用=拷貝,而不是調用智能指針的構造函數,如下:
int *q = new int(1234); shared_ptr<int> p = shared_ptr<int>(q);但是不能下面這樣寫: int *q = new int(1234); shared_ptr<int> p(shaared_ptr<int>(q)); 如果這樣寫了,*p會得到1(不知道為啥),p.use_count()和p.get()都會報錯(也不知道為啥)增加部分,下面是unique_ptr的幾個例子,unique_ptr的定義類似于shared_ptr
#include <iostream> #include <memory> #include <string> using namespace std; int main() {unique_ptr<int> p1(new int(3123));//用內置指針去構造unique_ptr,shared_ptr非常類似cout << *p1 << endl;unique_ptr<int> p2(p1.release());//把p1的值給p2,p1.release()返回p1的指針cout << *p2 << endl;//一會可以用這個動態指針構造一個shared_ptr或者unique_ptrint *k = new int(1234); //用k構造一個shared_ptr,完全可以,但是用非動態指針是不可以的shared_ptr<int> p4(k);cout << *p4 << endl; //pi是非動態指針,不可以用來初始化(用構造函數初始化)智能指針,但是pi2可以的int ix =1024,*pi =&ix,*pi2 = new int(2048);typedef unique_ptr<int> IntP; //下面這句是不可以的,ix不是動態指針//IntP p0(ix); 不合法 //下面當然可以IntP p3(pi2);cout << *p3 << endl; //下面當然可以的IntP p5(new int(2048));cout << *p5 << endl; //下面這個當然不可以,普通指針是不可以的//IntP p6(pi); //下面不可以//IntP p7(&ix); //下面這個不可以,get()不能初始化智能指針//IntP p8(pi2.get());return 0; }?
總結
以上是生活随笔為你收集整理的关于混合使用智能指针和内置指针的自己的问题和自己的见解(问题搜集中)这个帖子有待解决的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pygame中rect 初探
- 下一篇: pygame.rect中 Rect类 属