std::shared_ptr (c++11)

std::shared_ptr です。auto_ptr が deprecated(廃止予定)になりましたので、今後はこの shared_ptr および unique_ptr がスマートポインタの主流になっていくことでしょう。

 

 

 

1. shared_ptr を使ってみる

まずは shared_ptr を使ってみます。unique_ptr とほとんど同じ感じで使用できますが、shared_ptr はコピーできます。

 

1-1. その1

最初にシンプルな shard_ptr 使用例を紹介します。

 

shared_ptr を直接使用する例を記載します。

int 型の生成は、以下のように使用します。

std::shared_ptr up(new int);

 

値の初期化を一緒に行いたい場合、以下のように使用します。下記例は 10 で初期化しています。

std::shard_ptr up(new int(10));

 

配列を確保する場合は、以下のように使用します。

std::shared_ptr arr_sp(new int[5]);

 

配列の値を初期化と一緒に行いたい場合、以下のように使用します。下記例は {1,2,3,4,5} で初期化しています。

std::shared_ptr arr_up(new int[5]{1,2,3,4,5});

 

make_shared による例を記載します。

int 型の生成は、以下のように使用します。

auto sp = std::make_shared<int>();

 

値の初期化を一緒に行いたい場合、以下のように使用します。下記例は 77 で初期化しています。

auto up = std::make_shared<int>(77);

 

配列を確保する場合、以下のように使用します。下記例では、配列数 5 です。
make_shared を使って初期化を一緒に行うことはできないようです。

auto arr_up = std::make_shared<int[]>(5); // 要素はデフォルト初期化(ゼロでない場合あり)
for (int i = 0; i < 5; ++i) {
    arr_up[i] = (i + 1) * 10;
}

 

 

上記内容を含む c++ プログラムを以下で紹介します。

 

ソースコード:

["shared_ptr_01.cpp"]

#include <iostream>     // for std::cout
#include <new>          // for std::nothrow, placement new
#include <memory>       // for std::make_shared

/**
 * @brief std::shared_ptr, std::make_shared のシンプルなサンプル
 */

int main() {
    std::cout << "-- shared_ptr simple examples start --\n";

    // 1) 単一 int の std::shared_ptr
    {
        std::shared_ptr<int> sp(new int(10));
        std::cout << "*sp = " << *sp << "\n";
        // delete は自動的に行われる
    }

    // 2) int 配列の std::shared_ptr
    {
        std::shared_ptr<int[]> arr_sp(new int[5]{1,2,3,4,5});
        for (int i = 0; i < 5; ++i) {
            std::cout << "arr_sp[" << i << "] = " << arr_sp[i] << "\n";
        }
        // delete[] は自動的に行われる
    }

    // 3) 単一 int 生成、std::make_shared 版
    {
        auto sp = std::make_shared<int>(77);
        std::cout << "shared_ptr owns = " << *sp << "\n";
        // delete は自動的に行われる
    }
 
    // 4) 配列 int 生成、std::make_shared 配列版(C++20 以降)
    {
        auto arr_sp = std::make_shared<int[]>(5);   // 要素はデフォルト初期化(ゼロでない場合あり)
        for (int i = 0; i < 5; ++i) {
            arr_sp[i] = (i + 1) * 10;
        }
        std::cout << "make_shared<int[]> contents:";
        for (int i = 0; i < 5; ++i) {
            std::cout << ' ' << arr_sp[i];
        }
        std::cout << '\n';
        // delete[] は自動的に行われる
    }

    std::cout << "-- shared_ptr simple examples end --\n";
   return 0;
}

 

ビルド方法:

g++ -std=c++23 -g -Wall -Wextra -Wpedantic shared_ptr_01.cpp -o shared_ptr_01.out

 

実行結果:

$ ./shared_ptr_01.out 
-- shared_ptr simple examples start --
*sp = 10
arr_sp[0] = 1
arr_sp[1] = 2
arr_sp[2] = 3
arr_sp[3] = 4
arr_sp[4] = 5
shared_ptr owns = 77
make_shared<int[]> contents: 10 20 30 40 50
-- shared_ptr simple examples end --
$ 

 

 

 

1-2. その2

前の節で shared_ptr の簡単な使用方法について記載しました。

でも「本当に解放処理を自動的にやってくれてるのか心配」ですよね。

本節では、shared_ptr で class インスタンスを生成して、delete 無しで自動的にデストラクタが実行されることを確認してみます。

 

[ソースコード: "shared_ptr_cpp"]

#include "stdafx.h"

#include <iostream>
#include <string>
#include <memory>
#include <vector>

using namespace std;

struct Data {
    int id;
    std::string name;

    Data()
        : Data(0, "") {}
    Data(int id, const std::string& name)
        : id(id), name(name)
    {
        std::cout << "ctor" << std::endl;
    }

    ~Data()
    {
        std::cout << "dtor" << std::endl;
    }
};

int main()
{
    {
        vector<shared_ptr<Data>> v1;

        v1.push_back(shared_ptr<Data>(new Data(1, "foo")));
        v1.push_back(shared_ptr<Data>(new Data(2, "var")));

        for (auto data : v1) {
            cout << data->id << ", " << data->name << endl;
        }
    }

    {
        vector<shared_ptr<Data>> v2;

        v2.emplace_back(new Data(3, "foo"));
        v2.emplace_back(new Data(4, "bar"));

        for (auto data : v2) {
            cout << data->id << ", " << data->name << endl;
        }
    }

    return EXIT_SUCCESS;
}

 

実行結果

デストラクタが自動的に実行されてメモリ解放が行われていることがわかります。

 

評価環境:

 

 

1-3. その3

Let's boost のホームページからサンプルプログラムを引用、少し修正して以下に掲載します。

#include <iostream>   // cout, EXIT_SUCCESS
#include <string>     // string
#include <memory>     // shared_ptr
#include <vector>     // vector

using namespace std;

int main(int argc, char* argv[])
{
    typedef shared_ptr<string> strPtr;

    auto s = strPtr(new string("pen."));
    vector< strPtr > v;

    // vectorに入れたり。
    v.push_back( strPtr(new string("this")) );
    v.push_back( strPtr(new string("is")) );
    v.push_back( strPtr(new string("a")) );
    v.push_back(s);

    cout << *s << endl;
    
    // sをpush_backで他にコピーしたからと言って使えなくなったりしない。
    // auto_ptr, unique_ptr だと使えなくなる。

    // vector に保存した文字列を出力
    for ( strPtr pStr : v)       // ranged-for で表記
    {
        cout << *pStr << " ";
    }
    cout << endl;

    return EXIT_SUCCESS;
}
// ここで全て delete される

 

出力結果:

 

評価環境:

 

 

2. 関数の引数に使う

std::shared_ptr を関数の引数に使用する例を紹介します。

 

2-1. その1

関数の引数に shared_ptr を渡してみます。
関数に shared_ptr を渡したり、関数の中で shared_ptr の値を変更したり、といったことができます。

 

[ソースコード: "function_argument_sample.cpp"]

/**
 * @file function_argument_sample_01.cpp
 * @brief shared_ptr を関数引数として渡す際の動作をデモンストレーションするサンプルプログラム
 * 
 * このプログラムは、std::shared_ptr を使用したオブジェクトの所有権と参照カウントの管理を、
 * 関数引数として渡すさまざまな方法(const参照、参照渡し、値渡し)を通じて説明します。
 * 具体的には、以下の機能をサンプルとして実装しています:
 * - inspect 関数: shared_ptr を const 参照で受け取り、内容を表示(読み取り専用)。
 * - resetByRef 関数: shared_ptr を参照で受け取り、オブジェクトを差し替える。
 * - takeOwnership 関数: shared_ptr を値渡しで受け取り、参照カウントを増やして所有権を共有。
 * - makePerson 関数: Person オブジェクトを生成して shared_ptr で返すファクトリ関数。
 * 
 * main 関数では、これらの関数を呼び出して shared_ptr の動作を確認します。
 * プログラムの実行により、参照カウントの増減や所有権の移転を理解できます。
 */
#include <iostream> // for std::cout
#include <memory>   // for std::shared_ptr
#include <string>   // for std::string

/**
 * @brief 簡易的な Person クラス(サンプル用)
 */
class Person {
private:
    std::string name_;
    std::string phone_;

public:
    Person(const std::string& name, const std::string& phone)
        : name_(name), phone_(phone) {}

    const std::string& getName() const { return name_; }
    const std::string& getPhone() const { return phone_; }
    void setName(const std::string& name) { name_ = name; }
    void setPhone(const std::string& phone) { phone_ = phone; }
};

/**
 * @brief shared_ptr を読み取り専用で受け取り内容を表示する
 * @param person コンテンツを参照する const 参照の shared_ptr
 */
void inspect(const std::shared_ptr<Person>& person)
{
    if (person) {
        std::cout << "inspect: " << person->getName() << ", " << person->getPhone() << "\n";
    } else {
        std::cout << "inspect: (null)\n";
    }
}

/**
 * @brief shared_ptr の参照を受け取り差し替える
 * @param person 差し替える対象の shared_ptr への参照
 */
void resetByRef(std::shared_ptr<Person>& person)
{
    person = std::make_shared<Person>("replaced", "000-0000-0000");
}

/**
 * @brief shared_ptr を値渡しで受け取り参照カウントを増やす
 * @param person コピーを受け取る shared_ptr
 */
void takeOwnership(std::shared_ptr<Person> person)
{
    if (person) {
        std::cout << "takeOwnership: received " << person->getName() << "\n";

        // 所有権を共有しているので内容を変更できる
        person->setName("john");
        person->setPhone("012-3456-7890");
    } else {
        std::cout << "takeOwnership: (null)\n";
    }

    // person はここでスコープを抜けると参照カウントが減る
}

/**
 * @brief Person を生成して所有権を返すファクトリ関数
 * @param name 氏名
 * @param phone 電話番号
 * @return 所有権を持つ unique_ptr<Person>
 */
std::shared_ptr<Person> makePerson(const std::string& name, const std::string& phone)
{
    return std::make_shared<Person>(name, phone);
}

int main()
{
    std::cout << "-- unique_ptr function argument sample start --\n";

    // 1) makePerson で生成して戻り値で受け取る
    auto p1 = makePerson("alice", "111-1111-1111");
    inspect(p1);

    // 2) resetByRef で参照を渡して差し替える
    resetByRef(p1);
    inspect(p1);

    // 3) takeOwnership に値渡しで渡す(コピーにより参照カウントが増える)
    auto p2 = makePerson("bob", "222-2222-2222");
    takeOwnership(p2);
    inspect(p2);    // p2 はまだ有効(shared_ptr はコピーにより共有される)
                    // 内容も変更できる

    // 4) inspect に null を渡す
    std::shared_ptr<Person> empty;
    inspect(empty);

    std::cout << "-- unique_ptr function argument sample end --\n";
    return 0;
}

 

ビルド方法 (g++):

$ g++ -std=c++23 -Wall -Wextra -Wpedantic function_argument_sample_01.cpp -o function_argument_sample.out
$ 

 

実行結果:

$ ./function_argument_sample.out
-- unique_ptr function argument sample start --
inspect: alice, 111-1111-1111
inspect: replaced, 000-0000-0000
takeOwnership: received bob
inspect: john, 012-3456-7890
inspect: (null)
-- unique_ptr function argument sample end --
$

 

 

2-2. その2

もう少し複雑な適用例を示します。
クラスと関数オーバーロードへの適用を例に示します。
smart_ptr が最後にちゃんと解放されていることがわかります。
smart_ptr と合わせて生のポインタとオート変数への適用も併記するので、使い方などを比較してみてください。

 

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>
#include <iostream>     // cout, endl
#include <string>       // string
#include <memory>       // shared_ptr

using namespace std;


class Person{
private:
    string  name_;
    string  phone_;

public:
    Person()
        : Person("", "")                        // 委譲コンストラクタ、VS2013以降 OK、VS2012以前 NG
//      : name_(""), phone_("")                 // VS2012以前はこちらで
    {
    }

    Person(Person& rhs)
        : Person(rhs.name_, rhs.phone_)         // 委譲コンストラクタ、VS2013以降 OK、VS2012以前 NG
//      : name_(rhs.name_), phone_(rhs.phone_)  // VS2012以前はこちらで
    {
    }

    Person(string name, string phone)
        : name_(name), phone_(phone)
    {
        cout << "Person::Person(" << name_ << ")" << endl;
    }

    virtual ~Person()
    {
        cout << "Person::~Person(" << name_ << ")" << endl;
    }

    const std::string getName() const
    {
        return name_;
    }

    const std::string getPhone() const
    {
        return phone_;
    }
};


/*==================================*/
/* グローバルな演算子オーバーロード */
/*==================================*/
// shared_ptr<Person> 用
std::ostream& operator<<(std::ostream& os, const shared_ptr<Person> rhs)
{
    return (os << '(' << rhs->getName() << ',' << rhs->getPhone() << ')');
}

// Person* 用
std::ostream& operator<<(std::ostream& os, const Person* rhs)
{
    return (os << '(' << rhs->getName() << ',' << rhs->getPhone() << ')');
}

// Person 用
std::ostream& operator<<(std::ostream& os, const Person& rhs)
{
    return (os << '(' << rhs.getName() << ',' << rhs.getPhone() << ')');
}

// shared_ptr<Person> 用
void PrintPerson(shared_ptr<Person> person)
{
    cout << person << endl;
}

// Person* 用
void PrintPerson(Person* person)
{
    cout << person << endl;
}

// Person 用
void PrintPerson(Person& person)
{
    cout << person << endl;
}


int _tmain(int argc, _TCHAR* argv[])
{
    /*========*/
    /* 前処理 */
    /*========*/
    shared_ptr<Person> foo(new Person("foo", "090-****-0123"));
    shared_ptr<Person> bar(new Person("bar", "090-****-5555"));

    auto ptPerson = new Person("raw pointer person", "050-****-1234");
    Person autoPerson("auto person", "090-****-1943");

    /*========*/
    /* 処理部 */
    /*========*/
    PrintPerson(foo);
    PrintPerson(bar);
    PrintPerson(ptPerson);
    PrintPerson(autoPerson);

    /*========*/
    /* 後処理 */
    /*========*/
    delete ptPerson;             // 生のポインタは delete による解放が必要です。

    return EXIT_SUCCESS;
}

 

実行結果

foo, bar の2つの smart_ptr がちゃんと解放されていることがわかります。

 

 

3. shared_ptr で動的配列を使う

3-1. c++17 以前の環境の場合

shared_ptr はポインタが無効になった時 delete を使用します。つまり delete[]を必要とする動的配列を使用する場合は上記のような方法そのままでは使用できません。 boost::shared_array みたいなものは 標準c++ にはありません。
ただ、std::default_delete は配列に対する特殊化が提供されています。これ(std::default_delete)を使って shared_ptr で動的配列を使用する例を以下で紹介します。

 

■参考URL

 

スマートポインタの本家 boost はバージョン 1.53 以降で boost::shared_ptr が配列(T[])に対応しました。標準にもいずれフィードバックされることでしょう。(c++17 で採用されました。)
また標準ではC++11で採用された std::unique_ptr は delete, delete[] を自動判断する機構が入っています。std::unique_ptr を使用することも検討しましょう。

 

#include <iostream>     // cout, EXIT_SUCCESS
#include <string>       // string
#include <memory>       // shared_ptr, default_delete
#include <vector>       // vector

using namespace std;

struct Data {
    int id;
    std::string name;

    Data()
        : Data(0, ""){}
    Data( int id, const std::string& name )
        : id(id), name(name)
    {
        std::cout << "ctor" << std::endl;
    }

    ~Data()
    {
        std::cout << "dtor" << std::endl;
    }
};

void disp( std::shared_ptr<Data> p, size_t n )
{
    for (std::size_t i = 0; i < n; ++i) {
        const Data& x = p.get()[i];
        std::cout << x.id << ", " << x.name << std::endl;
    }
}

int main()
{
    std::size_t n = 3;
    std::shared_ptr<Data> p(new Data[n], std::default_delete<Data[]>());
   
    p.get()[0] = { 3, "Alice" };
    p.get()[1] = { 1, "Bob" };
    p.get()[2] = { 4, "Carol" };

    disp(p, n);

    std::cout << "end main" << std::endl;
}

確かに配列をスマートポインタで扱えるようになりましたが、get()で生のポインタを取り出ししたのちに[]により指定する必要がある、など少々不便な感じがします。つまり shared_ptr は[]のオペレータが無いのです。boost::shared_array の方が使い勝手が良かったように感じます。c++14 で shared_array が追加されるか、shared_ptr に []のオペレータが追加されるか、などを期待します。(後日追記: c++17 で採用されました。)
配列を使う場合はコンテナ(std::vector, std::array, std::list)を使いなさい、ってのが背景にあるのかもしれません。

 

 

3-2. c++17 以降の環境の場合

c++17 にて shared_ptr が T[] および T[N] に対応しました。これで unique_ptr と同じように簡単に配列を実装できます。

 

#include "stdafx.h"

#include <iostream>
#include <memory>

using namespace std;

int main()
{
    // std::shared_ptr の例
    // default_delete の特殊化宣言は不要。delete[]が実行される。
    // []演算子もある。
    size_t  n = 10;
    shared_ptr<int[]> data(new int[n]);

    cout << "std::shared_ptr<int> : ";
    for (size_t i = 0; i < n; ++i) {
        data[i] = i;
    }
    for (size_t i = 0; i < n; ++i) {
        cout << data[i] << " ";
    }
    cout << endl;

    return EXIT_SUCCESS;
}

 

評価環境:

 

 

4. malloc, free を shared_ptr に置き換える

4-1. c++17 以前の環境の場合

c 言語で規定されている malloc, calloc でメモリを動的に取得した場合、解放に使用する関数は delete や delete[] ではなく free を使用します。デアロケータを指定することで shared_ptr のメモリ解放を free で行えるようにします。

 

#include <iostream>     // cout, EXIT_SUCCESS
#include <memory>       // shared_ptr
#include <cstdlib>      // malloc, free

using namespace std;

int main()
{
    const size_t    n = 256;

    shared_ptr<int> memory( static_cast<int*>(malloc(n*sizeof(int))), free);

    // いちおうメモリ取得できたかを確認のうえで使用しましょう。
    if ( memory.get() != nullptr ){
        for ( size_t i=0; i<n; ++i ){
            memory.get()[i] = (int)i;
        }
        for (size_t i = 0; i < n; ++i){
            cout << memory.get()[i] << ", ";
        }
        cout << endl;
    }

    return EXIT_SUCCESS;
    // ここで free が実装されて memory を開放
}

 

 

4-2. c++17 以降の環境の場合

前述の例だと "memory.get()[i]" というに配列へアクセスするのが気持ち悪い。やっぱり "memory[i]" って使いたいです。
c++17 にて shared_ptr が T[] および T[N] に対応しました。これで unique_ptr と同じように簡単に配列を実装できる、と思われます。

VS2019でテストした感じだと意図通りに "memory[i]" で使えて、ちゃんと free もやってくれてそうに見えます。
unique_ptr と使い方が違うことが不安材料です。

#include <iostream>     // cout, EXIT_SUCCESS
#include <memory>       // shared_ptr, unique_ptr
#include <cstdlib>      // malloc, free

using namespace std;

int main()
{
    const size_t    n = 256;

    std::shared_ptr<int[]> memory(static_cast<int*> (malloc(n * sizeof(int))), std::free);
    if (memory.get() == nullptr) {
        // malloc失敗
    }
    else {
        // malloc成功
        for (size_t i = 0; i < n; ++i) {
            memory[i] = (int)i;
        }
        for (size_t i = 0; i < n; ++i) {
            cout << memory[i] << ", ";
        }
        cout << endl;
    }

    return EXIT_SUCCESS;
    // ここで free が実装されて memory を開放
}

 

 

5. fopen, fclose を shared_ptr に置き換える

これは実装例をいくつか書いてみます。しっくりくるやつを使ってみてください。

シンプルにやるとこんな感じでしょうか。

#include <stdio.h>  // fopen, fclose
#include <stdlib.h>
#include <memory>   // shared_ptr

#pragma warning(disable : 4996) // fopen, fclose の使用がエラーになるため

void custom_fclose(FILE* fp){
    if (fp != nullptr){
        fclose(fp);
    }
}

int main(int argc, char* argv[])
{
    std::shared_ptr<FILE>   fp(fopen("fopen_test.txt", "w"), custom_fclose);

    if (fp.get() != nullptr){
        // fopen成功
        fprintf(fp.get(), "test\n");
    }

    return EXIT_SUCCESS;
    // ここで custom_fclose が自動実行されます
}

 

これを Lambda式 で記載するとこんな感じでしょうか。

#include <stdio.h>          // FILE, fopen, fclose
#include <stdlib.h>
#include <memory>           // shared_ptr

#pragma warning(disable : 4996)

int main(int argc, char* argv[])
{
    std::shared_ptr<FILE>   fp(fopen("fopen_test.txt", "w"), [&](FILE* fp){
        if (fp != nullptr){
            fclose(fp);
        }
    });

    // 一応ファイルオープンの成功/失敗を確認してからファイルを使用
    if (fp.get() != nullptr){
        // fopen成功
        fprintf(fp.get(), "test\n");
    }

    return EXIT_SUCCESS;
    // ここで custom_fclose が自動実行されます
}

 

ファクトリーパターン的に shared_ptr を返す関数を作成するならばこんな感じでしょうか。

#include <cstdio>       // fopen, fclose
#include <iostream>     // cout, EXIT_SUCCESS
#include <memory>       // shared_ptr

using namespace std;

#pragma warning(disable : 4996)

std::shared_ptr<std::FILE> make_file(const char * filename, const char * flags)
{
    // fclose に NULL を渡して実行してはいけない。
    // このため下記のような分岐処理が必要となる。
    std::FILE * const fp = std::fopen(filename, flags);
    return fp ? std::shared_ptr<std::FILE>(fp, std::fclose) : std::shared_ptr<std::FILE>();
}

int main()
{
    auto fp = make_file("hello.txt", "wb");

    // fp.get() をチェック
    // fopen に失敗していたら fp.get() は NULL
    if (fp.get()){
        fprintf(fp.get(), "Hello world.");
    }
}

私的には Lambda式 を使った2番目のやつが一番シンプルで好きかな。

 

 

6. make_shared

c++11 から make_shared が加わりました。shared_ptr 直接使用せず make_shared によるコーディングが推奨されています。

 

[ソースコード: "make_shared_01.cpp"]

#include <iostream>     // for std::cout
#include <new>          // for std::nothrow, placement new
#include <memory>       // for std::make_shared

/**
 * @brief std::shared_ptr, std::make_shared のシンプルなサンプル
 */

int main() {
    std::cout << "-- shared_ptr simple examples start --\n";

    // 1) 単一 int 生成、std::make_shared 版
    {
        auto sp = std::make_shared<int>();
        std::cout << "shared_ptr owns = " << *sp << "\n";
        // delete は自動的に行われる
    }

    // 2) 単一 int 生成、std::make_shared 版
    {
        auto sp = std::make_shared<int>(77);
        std::cout << "shared_ptr owns = " << *sp << "\n";
        // delete は自動的に行われる
    }

    std::cout << "-- shared_ptr simple examples end --\n";
   return 0;
}

 

ビルド方法:

g++ -std=c++20 -g -Wall -Wextra -Wpedantic make_shared_01.cpp -o make_shared_01.out

 

実行結果:

$ ./make_shared_01.out 
-- shared_ptr simple examples start --
shared_ptr owns = 0
shared_ptr owns = 77
-- shared_ptr simple examples end --
$ 

 

 

 

class インスタンスの生成もやってみます。

 

[ソースコード: "make_shared_02.cpp"]

#include <iostream>     // cout, endl
#include <string>       // string
#include <memory>       // shared_ptr, make_shared
#include <vector>       // vector

using namespace std;

class Data {
private:
    int id_;
    std::string name_;

public:
    Data()
        : Data(0, "") {}
    Data(int id, const std::string& name)
        : id_(id), name_(name)
    {
        std::cout << "ctor" << std::endl;
    }

    ~Data()
    {
        std::cout << "dtor" << std::endl;
    }

    int GetId()
    {
        return id_;
    }

    std::string GetName()
    {
        return name_;
    }
};


int main()
{
    vector<shared_ptr<Data>> v1;

    v1.push_back(make_shared<Data>(1, "foo"));
    v1.push_back(make_shared<Data>(2, "bar"));

    for (auto data : v1) {
        cout << data->GetId() << ", " << data->GetName() << endl;
    }

    return EXIT_SUCCESS;
}

 

実行結果

 

評価環境:

 

 

7. make_shared 配列版

c++17 にて shared_ptr が T[] および T[N] に対応しました。make_shared も c++20 で T[] および T[N] に対応しました。

使用例を紹介したいと思います。

 

配列を確保する場合、以下のように使用します。下記例では、配列数 5 です。
make_shared を使って初期化を一緒に行うことはできないようです。

auto arr_up = std::make_shared<int[]>(5); // 要素はデフォルト初期化(ゼロでない場合あり)
for (int i = 0; i < 5; ++i) {
    arr_up[i] = (i + 1) * 10;
}

 

 

上記内容を含む c++ プログラムを以下で紹介します。

 

[ソースコード: "make_shared_03.cpp"]

#include <iostream>     // for std::cout
#include <new>          // for std::nothrow, placement new
#include <memory>       // for std::make_shared

/**
 * @brief std::shared_ptr, std::make_shared のシンプルなサンプル
 */

int main() {
    std::cout << "-- make_shared simple examples start --\n";

    // 1) 配列 int 生成、std::make_shared 配列版(C++20 以降)
    {
        const size_t array_size = 5;
        auto arr_sp = std::make_shared<int[]>(array_size);   // 要素はデフォルト初期化(ゼロでない場合あり)
        for (size_t i = 0; i < array_size; ++i) {
            arr_sp[i] = (i + 1) * 10;
        }

        std::cout << "make_shared<int[]> contents: ";
        for (size_t i = 0; i < array_size; ++i) {
            std::cout << ' ' << arr_sp[i];
        }
        std::cout << '\n';
        // delete[] は自動的に行われる
    }

    std::cout << "-- make_shared simple examples end --\n";
   return 0;
}

 

ビルド方法:

g++ -std=c++20 -g -Wall -Wextra -Wpedantic make_shared_03.cpp -o make_shared_03.out

 

実行結果:

$ ./make_shared_03.out 
-- make_shared simple examples start --
make_shared<int[]> contents: 10 20 30 40 50
-- make_shared simple examples end --
$ 

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

Copyright © 2013 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

参考

 


 

変更履歴

2025-11-30 - 2-1._その1」内容を差し替え
2025-11-20 - 1-1._その1 を追加
2022-07-13 - ページデザイン更新
2018-05-04 - いろいろアップデート。c++17 に関わる make_shared, 配列対応版の shared_ptr, などのネタを追加。
2014-09-06 - ソースコードを表記を「google-code-prettify」によるものへ変更
2014-03-09 - 追記/修正
2013-12-01 - 新規作成

 

Programming Items トップページ

プライバシーポリシー