Skip to content

Instantly share code, notes, and snippets.

@hmito
Last active June 15, 2020 04:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hmito/32d8ad0c7f216db73239 to your computer and use it in GitHub Desktop.
Save hmito/32d8ad0c7f216db73239 to your computer and use it in GitHub Desktop.
C++11スマートポインタ入門 ref: https://qiita.com/hmito/items/db3b14917120b285112f
//通常のポインタがほしい時には、get関数を使う。
//ポインタの所有権はunique_ptrが保持し続ける
int* pint;
pint = ptr.get();
//所有権自体を放棄する場合は、release関数を使う
//この場合、メモリの解放自体は自分で行う必要がある
pint = ptr.release();
delete pint;
{
//型名[]をテンプレート引数に指定することで、配列も扱える
std::unique_ptr<int[]> ptrArray(new int[10]);
//配列型の場合operator[](size_t)を使うことができる
for(int i=0;i<10;++i){
ptrArray[i]=i;
}
}//配列型の場合、自動的にdelete[]が呼ばれて解放される。
//コンストラクタや、reset関数を使ってのメモリ割り当てが可能
std::shared_ptr<int> ptr(new int(10));
std::shared_ptr<int> ptr2;
ptr2.reset(new int(10));
//make_shared関数を使うと、効率よくメモリを確保できる(C++11から使える)
std::shared_ptr<int> ptr3=std::make_shared<int>(10);
//複数の引数を持つコンストラクタも、make_sharedから呼び出せる
typedef std::pair<int,double> int_double_t;
std::shared_ptr<int_double_t> ptr4=std::make_shared<int_double_t>(10,0.4);
//コピーコンストラクタや、コピー代入演算子もOK
//所有権は、ptr、ptr2、ptr3の三者が保持する
std::shared_ptr<int> ptr=std::make_shared<int>(10);
std::shared_ptr<int> ptr2(ptr); //ok ptrとptr2で所有権を共有
std::shared_ptr<int> ptr3;
ptr3=ptr; //ok ptrとptr3で所有権を共有
//ムーブコンストラクタや、ムーブ代入演算子はOK
//この時、所有権は移動する
std::shared_ptr<int> ptr4(std::move(ptr)); //ok ptrの所有権がptr4に移動する
std::shared_ptr<int> ptr5;
ptr5=std::move(ptr2); //ok ptr2の所有権がptr5に移動する
//コンストラクタでunique_ptrからムーブ
//所有権がuptrからptrに移動する
std::unique_ptr<int> uptr(new int(10));
std::shared_ptr<int> ptr(std::move(uptr));
//代入演算子で、ムーブ
//こちらも同様に、所有権がuptr2からptr2に移動する
std::unique_ptr<int> uptr2(new int(10));
std::shared_ptr<int> ptr2;
ptr2=std::move(uptr2);
std::shared_ptr<int> ptr=std::make_shared<int>(10);
{
//ptrから所有権をコピー
std::shared_ptr<int> ptr2(ptr);
}//ここでptrのディストラクタが呼ばれ、ptr2は所有権を放棄
//ptrがまだ所有権を保有しているので、メモリは解放されていない
//引数なしやnullptrを引数としてreset関数を呼んでも、明示的に所有権を放棄できる
//ptrが所有権を放棄すると、所有権を持つポインタがなくなるので、ここでメモリ解放
ptr.reset();
std::shared_ptr<int> ptr;
//メモリの所有権を保持しているかどうかは、boolの文脈で使用することで判定できる
//所有していれば、trueを返す
if(ptr){
//---所有しているときの処理---
}
//bool変数への代入も可能
bool CanAccess=ptr;
//所有者の数を確認するには、use_count関数を使う
std::cout<<"use_count="<<ptr.use_count()<<std::endl;
//所有者が唯一であることを確認するには、unique関数を使う
//use_count()==1ならtrue, それ以外ならfalseとなる
if(ptr.unique()){
std::cout<<"unique"<<std::endl;
}
std::shared_ptr<std::string> pStr=std::make_shared<std::string>("test");
//operator*()でstring型呼び出し
// "test" と表示される
std::cout<<*pStr<<std::endl;
//operator->()で、string型のsize関数を呼び出せる
unsigned int StrSize=pStr->size();
std::shared_ptr<int> ptr=std::make_shared<int>(10);
//通常のポインタがほしい時には、get関数を使う。
//ポインタの所有権はshared_ptrが保持し続ける
int* pint;
pint=ptr.get();
{
//[]型名をテンプレート引数に指定することで、配列も扱える
//第2引数で、配列用にdeleterを指定
//deleterを明示的に指定する際には、make_sharedは使えない
std::shared_ptr<int> ptrArray(new int[10], std::default_delete<int[]>());
//operator[]は使えない
//代わりに、get関数からアクセスはできる
for(int i=0;i<10;++i){
//ptrArray[i]=i; //===ERROR===
ptrArray.get()[i]=i; //ok
}
}//default_delete<int[]>を指定しておけば、自動的にdelete[]が呼ばれて解放される。
//コンストラクタや代入演算子で、shared_ptrを受け取る
std::shared_ptr<T> sptr=std::make_shared<int>(10);
std::weak_ptr<T> wptr(sptr);
std::weak_ptr<T> wptr2;
wptr2=sptr;
//ポインタを直接受け取ることはできない
//std::weak_ptr<T> wptr3(new int(10)); //===ERROR===
std::shared_ptr<int> sptr=std::make_shared<int>(10);
std::weak_ptr<int> wptr(sptr);
//コピーコンストラクタや、コピー代入演算子もOK
std::weak_ptr<int> wptr2(wptr);
std::weak_ptr<int> wptr3;
wptr3=wptr;
//ムーブコンストラクタや、ムーブ代入演算子もOK
//この時、wptr2,wptr3は参照を失う
std::weak_ptr<int> wptr4(std::move(wptr2));
std::weak_ptr<int> wptr5;
wptr5=std::move(wptr3);
std::shared_ptr<int> sptr=std::make_shared<int>(10);
{
std::weak_ptr<int> wptr(sptr);
}//ディストラクタで参照を解放
std::weak_ptr<int> wptr2(sptr);
//reset関数で明示的に解放
wptr2.reset();
std::shared_ptr<int> sptr=std::make_shared<int>(10);
std::weak_ptr<int> wptr(sptr);
//参照先のメモリが解放されていないかどうかはexpired関数を使う
if(wptr.expired()){
std::cout<<"expired"<<std::endl;
}
//所有者の数を確認するには、use_count関数を使う
std::cout<<"use_count="<<wptr.use_count()<<std::endl;
std::shared_ptr<int> sptr=std::make_shared<int>(10);
std::weak_ptr<int> wptr(sptr);
{
//lock関数によって、参照先を保持するshared_ptrを取得する
std::shared_ptr<int> ptr=wptr.lock();
}
//コンストラクタの引数として、動的確保したメモリのアドレスを指定
std::unique_ptr<int> ptr(new int(10));
//reset関数を使って、後から代入することもできる
std::unique_ptr<int> ptr2;
ptr2.reset(new int(10));
//C++14以降であれば、make_unique関数を使うこともできる
std::unique_ptr<int> ptr3=std::make_unique<int>(10);
std::unique_ptr<int> ptr(new int(10));
//コピーコンストラクタや、コピー代入演算子はエラー
//std::unique_ptr<int> ptr2(ptr); //===ERROR===
std::unique_ptr<int> ptr3;
//ptr3=ptr; //===ERROR===
//ムーブコンストラクタや、ムーブ代入演算子はOK
//この時、所有権が移動する
std::unique_ptr<int> ptr4(std::move(ptr)); //ok ptrの所有権がptr4に移動する
std::unique_ptr<int> ptr5;
ptr5=std::move(ptr4); //ok ptr4の所有権がptr5に移動する
{
std::unique_ptr<int> ptr(new int(10));
}//ここでptrのディストラクタが呼ばれ、自動的に解放される
//引数なしやnullptrを引数としてreset関数を呼んでも、明示的に解放できる
std::unique_ptr<int> ptr2(new int(10));
ptr2.reset();
std::unique_ptr<int> ptr;
//メモリの所有権を保持しているかどうかは、boolの文脈で使用することで判定できる
//所有していれば、trueを返す
if(ptr){
//---所有しているときの処理---
}
//bool変数への代入でも、所有権の有無を取得可能
bool CanAccess=ptr;
std::unique_ptr<std::string> pStr(new std::string("test"));
//operator*()でstring型を参照
// "test" と表示される
std::cout<<*pStr<<std::endl;
//operator->()で、string型のsize関数を呼び出せる
unsigned int StrSize = pStr->size();
//int型のリソースをstorageから確保する
int* malloc_int_from_storage();
//int型のリソースをstorageから解放する
void free_int_from_storage(int* ptr);
#include<iostream>
#include<memory>
int main(){
//int型のメモリを動的に確保し、その所有権をauto_ptrに委ねる
std::auto_ptr<int> ptr(new int(10));
//operator*()で生ポインタのようにアクセスできる
for(int i=0;i<10;++i){
*ptr+=i;
}
std::cout<<"ptr="<<*ptr<<std::endl;
return 0;
}//ディストラクタ内で、自動的にptrの中身をdelete
#include<iostream>
#include<memory>
class hoge{
private:
std::auto_ptr<int> ptr;
public:
hoge(int val_):ptr(new int(val_)){}
int getValue()const{return *ptr;}
};
int main(){
//hogeのコンストラクタでint型を動的に確保しauto_ptrに委ねる
hoge Hoge(10);
//コピーコンストラクタで二つ目のhogeを作成
//この時Hoge.ptrからHoge.ptr2に所有権が移動!
hoge Hoge2(Hoge);
//Hogeの値を呼び出す
Hoge.getValue(); //===ERROR===
//実行時エラー!
//Hoge.ptrはすでに所有権を失っているので、アクセスできない
return 0;
}
#include<memory>
class hoge{
public:
std::shared_ptr<hoge> ptr;
};
int main(){
std::shared_ptr<hoge> pHoge1=std::make_shared<hoge>();
std::shared_ptr<hoge> pHoge2=std::make_shared<hoge>();
//Hoge1のメンバ変数で、pHoge2を参照する
pHoge1->ptr=pHoge2;
//Hoge2のメンバ変数で、pHoge1を参照する
pHpge2->ptr=pHoge1;
return 0;
}//shared_ptrのディストラクタが呼ばれるのに、確保した二つのhogeが解放されない。
#include<memory>
#include"memory_from_storage.hpp"
//free_int_from_storageを使ってメモリを解放する関数オブジェクトを定義する。
struct deleter_for_storage{
void operator()(int* ptr_){
free_int_from_sotrage(ptr_);
}
};
int main(){
//テンプレート第二引数で、deleterを指定する
std::unique_ptr<int, deleter_for_storage> ptr(malloc_int_from_storage());
//deleteではなく、free_int_from_storageがメモリ解放の際に呼ばれる。
return 0;
}
#include<iostream>
int main(){
int* ptr=new int(10);
for(int i=0;i<10;++i){
*ptr+=i;
}
std::cout<<"ptr="<<*ptr<<std::endl;
delete ptr; //これを忘れると、メモリリーク
return 0;
}
#include<memory>
class hoge{
private:
int* ptr;
public:
hoge(int val_){
if(val_>0)ptr=new int(val_);
}
~hoge(){delete ptr;}
};
int main(){
//hogeのコンストラクタでnewが呼ばれない
hoge Hoge(-1);
return 0;
}//=== ERROR=== ディストラクタでdeleteが呼ばれるので、動作は未定義!
#include<memory>
#include<iostream>
int main(){
//空のshared_ptrを作成
std::shared_ptr<int> ptr;
{
//intの所有権を持つ、ptr2を作成
std::shared_ptr<int> ptr2(new int(0));
//ptr2の所有権をptrにコピー、共有する
ptr=ptr2;
*ptr+=10;
*ptr2+=10;
}//ここで、ptr2のディストラクタが呼ばれる
//ptrも同一のメモリに対する所有権を持っているため、まだ解放はされない
//当然、ptrはまだ使用可能
std::cout<<"ptr="<<*ptr<<std::endl; //"ptr=20"と出力
}//ここで、ptrのディストラクタが呼ばれる
//メモリの所有権を持つポインタがいなくなったので、解放される
#include<iostream>
#include<memory>
class hoge{
private:
std::unique_ptr<int> ptr;
public:
hoge(int val_):ptr(new int(val_)){}
int getValue()const{return *ptr;}
};
int main(){
//hogeのコンストラクタでint型を動的に確保しunique_ptrに委ねる
hoge Hoge(10);
//unique_ptrはコピーできないので、
//コピーコンストラクタで作成しようとすると、コンパイルエラー
//hoge Hoge2(Hoge); //===ERROR===
//明示的にmoveするならOK
hoge Hoge2(std::move(Hoge));
return 0;
}//auto_ptr同様、ディストラクタで自動的にメモリ解放
#include<memory>
class hoge{
public:
//shared_ptrで所有権を得る代わりに、weak_ptrで参照する
std::weak_ptr<hoge> ptr;
};
int main(){
std::shared_ptr<hoge> pHoge1=std::make_shared<hoge>();
std::shared_ptr<hoge> pHoge2=std::make_shared<hoge>();
//Hoge1のweak_ptrで、pHoge2を参照する
pHoge1->ptr=pHoge2;
//Hoge2のweak_ptrで、pHoge1を参照する
pHpge2->ptr=pHoge1;
}//所有権は、pHoge1, pHoge2しかそれぞれ持っていないので、正しく解放される
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment