カテゴリー【C/C++】
【C++】動的配列クラスstd::vectorにstd::shared_ptrを格納する
POSTED BY
2023-07-23
2023-07-23
【C++】new/deleteを撤廃しstd::shared_ptrを使うの続きです。
newした生ポインタをvectorに格納する行為はSegmentation faultへの第一歩だが、shared_ptrはptrライクな生クラスなので問題なく格納できる。
shared_ptrは、自身を参照する人がゼロ人になったら保持しているクラスと自分自身を破棄=保持クラスのデストラクタが呼ばれる=のだが、この挙動はvectorのサンプルを書くのが一番確認しやすい。
C/C++ | vector.cpp | GitHub Source |
#include <iostream> #include <string> #include <memory> #include <vector> class A { std::string mName; public: A(void) { std::cout << "A constructor" << std::endl; mName = std::string("えーでふぉると"); } A(std::string name) { std::cout << "A constructor" << std::endl; mName = name; } virtual ~A(void) { std::cout << "A destructor" << std::endl; } void hello(void) { std::cout << "A said こんにちは my name is" << mName << std::endl; } }; void sample_1(void) { std::cout << "enter sample_1" << std::endl; std::vector<std::shared_ptr<A>> vec = std::vector<std::shared_ptr<A>>(); std::shared_ptr<A> a1 = std::make_shared<A>(std::string("えーいち")); std::shared_ptr<A> a2 = std::make_shared<A>(std::string("えーに")); std::shared_ptr<A> a3 = std::make_shared<A>(std::string("えーさん")); std::shared_ptr<A> a4 = std::make_shared<A>(std::string("えーよん")); vec.push_back(a1); vec.push_back(a2); vec.push_back(a3); vec.push_back(a4); std::cout << "vector count=" << vec.size() << std::endl; vec.at(0)->hello(); vec.back()->hello(); std::cout << "before vector clear" << std::endl; vec.clear(); std::cout << "after vector clear" << std::endl; std::cout << "leave sample_1" << std::endl; } void sample_2(void) { std::cout << "enter sample_2" << std::endl; std::vector<std::shared_ptr<A>> vec = std::vector<std::shared_ptr<A>>(); vec.push_back(std::make_shared<A>(std::string("えーいち"))); vec.push_back(std::make_shared<A>(std::string("えーに"))); vec.push_back(std::make_shared<A>(std::string("えーさん"))); vec.push_back(std::make_shared<A>(std::string("えーよん"))); std::cout << "vector count=" << vec.size() << std::endl; vec.at(0)->hello(); vec.back()->hello(); std::cout << "before vector clear" << std::endl; vec.clear(); std::cout << "after vector clear" << std::endl; std::cout << "leave sample_2" << std::endl; } int main(int argc, char **argv) { std::cout << "enter main" << std::endl; sample_1(); sample_2(); std::cout << "leave main" << std::endl; return 0; }
関数sampleではクラスAの実体をshared_ptrで4つ確保(と同時に名前を与え)、shared_ptrポインタを動的配列クラスvectorに格納している。
shared_ptr破棄の挙動を確認する前に、C++で最も多用するstd::vectorの基本となる箇所を以下抜粋。
Aのshared_ptrを格納するvectorクラスの宣言・スタック変数として初期化確保
std::vector<:shared_ptr>> vec = std::vector<:shared_ptr>>(); </:shared_ptr></:shared_ptr>
配列の末尾に格納
vec.push_back(a1);
現在の要素数を取得する
std::cout 任意のインデックスの要素を取得する。先頭を取得するには0。最後の要素を取得するにはbackを使うか、vec.at(vec.size() -1)とすればよい。 <pre> vec.at(0)->hello(); vec.back()->hello();vectorをカラにするにはclearする。
vec.clear();コンパイル、実行結果
g++ vector.cpp ./a.out enter main enter sample_1 A constructor A constructor A constructor A constructor vector count=4 A said こんにちは my name isえーいち A said こんにちは my name isえーよん before vector clear after vector clear leave sample_1 A destructor A destructor A destructor A destructor enter sample_2 A constructor A constructor A constructor A constructor vector count=4 A said こんにちは my name isえーいち A said こんにちは my name isえーよん before vector clear A destructor A destructor A destructor A destructor after vector clear leave sample_2 leave mainsample_1では、vec.clearとした段階では、vecはカラになるが、その場では4つあるクラスAはいずれも破棄されない(デストラクタが呼ばれていない)。 これはsample1の関数内でスタック変数としてshared_ptr a1..a4を宣言確保しており、vecをカラにしてもこのsample1関数自体がまだa1..a4としてポインタを保有している=参照している人がまだ居るから=である。 sample_1関数を抜けると同時に、スタック変数a1..a4は廃棄されるので、ここで最後にAのデストラクタが呼ばれることになる。 対してsample_2では、スタック変数として宣言せず、vec.push_backに引数としてそのままmake_sharedして渡しているため、保有している人はvecただ1人である。よって今度は、vec.clearした時点で、もうAを参照している人はゼロになるため、その場でAのデストラクタが呼ばれshared_ptrが破棄されている様子が出力により確認できる。 C++公式日本語リファレンス https://cpprefjp.github.io/reference.html C++公式日本語リファレンス/std::shared_ptr https://cpprefjp.github.io/reference/memory/shared_ptr.html
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ
※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!ご連絡は以下アドレスまでお願いします★
【キーワード検索】
【最近の記事】【全部の記事】
Intel Macbook2020にBootCampで入れたWindows11 Pro 23H2のBluetoothを復活させるWindowsのデスクトップ画面をそのまま配信するための下準備
WindowsでGPUの状態を確認するには(ASUS系監視ソフトの自動起動を停止する)
CORESERVER v1プランからさくらインターネットスタンダートプランへ引っ越しメモ
さくらインターネットでPython MecabをCGIから使う
さくらインターネットのPHPでAnalytics-G4 APIを使う
インクルードパスの調べ方
【Git】特定ファイルを除外する.gitignore
【Ubuntu/Debian】NVIDIA関係のドライバを自動アップデートさせない
【Python】Spacyを使用して文章から出発地と目的地を抜き出す
【人気の記事】【全部の記事】
進研ゼミチャレンジタッチをAndroid端末化する【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法
【Apache】サーバーに同時接続可能なクライアント数を調整する
GitLabにHTTPS経由でリポジトリをクローン&読み書きを行う
Windows版Google Driveが使用中と言われアンインストールできない場合
【Linux】iconv/libiconvをソースコードからインストール
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
Windows11+WSL2でUbuntuを使う【2】ブリッジ接続+固定IPの設定
【PHP】Mail/mimeDecodeを使ってメールの中身を解析(準備編)
Googleファミリーリンクで子供の端末の現在地がエラーで取得できない場合
【カテゴリーリンク】
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ