方法
// std::shared_ptr
# include <memory>
// boost::shared_ptr
# include <boost/shared_ptr.hpp>
auto main() -> int
{
boost::shared_ptr< int > b = boost::shared_ptr<int>( new int( 123 ) );
std::shared_ptr< int > s = std::shared_ptr<int>( x.get(), [x] ( ... ) mutable { } );
}
検証
挙動の確認
「方法」の比較的簡潔なコードに、挙動の確認に適当なブロックスコープと std::cout
などを仕込む例を紹介。
# include <iostream>
# include <memory>
# include <boost/shared_ptr.hpp>
using namespace std;
int main()
{
std::cout << "scope-A{\n";
{
std::cout << "scope-B{\n";
std::shared_ptr< int > s;
std::cout << "s = " << s << '\n';
{
std::cout << "scope-C{\n";
boost::shared_ptr< int > b = boost::shared_ptr< int >( new int( 123 ) );
std::cout << "b = " << b << '\n';
// 今回は解説の都合 b でキャプチャーすると紛らわしいので bc としてコピーキャプチャーする例示にします。
s = std::shared_ptr<int>( b.get(), [ bc = b ] ( ... ) mutable { std::cout << "reset bc in dtor lambda of s\n"; } );
std::cout << "s = " << s << '\n';
std::cout << "}scope-C\n";
}
std::cout << "s = " << s << '\n';
std::cout << "}scope-B\n";
}
std::cout << "}scope-A\n";
}
↑これをビルドして実行すると、↓こうなる。
scope-A{
scope-B{
s = 0
scope-C{
b = 0x1c595b0
s = 0x1c595b0
}scope-C
s = 0x1c595b0
}scope-B
reset bc in dtor lambda of s
}scope-A
-
scope-A{
:main
関数の関数スコープの始まり。 -
scope-B{
:std::shared_ptr< int > s
が宣言されるブロックスコープの始まり。 -
scope-C{
:boost::shared_ptr< int > b
が宣言、定義され、scope-B
のs
に対して「変換」が行われるブロックスコープの始まり。 -
}scope-C
: オブジェクトb
がスコープを外れ破棄されるタイミング。但し、「変換」が成功していればb
はs
のカスタムデリーターのラムダ式にbc
としてコピーキャプチャーされているため、b
が破棄されてもbc
はs
のスコープで生存する「はず」というタイミング。 -
}scope-B
: 「変換」が成功していればs
はscope-B
のb
と同じオブジェクトをこの時点までは間接参照できる「はず」の最後のタイミング。ここを超えるとオブジェクトs
もスコープにより破棄されるので、s
のカスタムデリーターに仕込んだbc
の破棄出力が得られる「はず」のタイミング。 -
}scope-A
: ↑の(5)とこの(6)の間にs
のカスタムデリーターによるbc
の破棄出力が得られている「はず」のタイミング。
と、いうわけで、外部から観測する挙動としては意図通りに「変換」できている事がわかる。