概要
グローバル空間に定義されたポインタ変数に、関数中で動的に確保したメモリへのポインタを保持するようなプログラムで、そのポインタが指すメモリを解放する必要があるかどうか知りたいです。
前提
確認として、私はそもそも動的に確保したメモリはプログラムが終わるまでに解放する必要があると教わりました。
しかし、先日グローバル空間に定義されたポインタに確保したメモリを割り当てて、そのまま解放しないプログラムと出会い、書いた人に確認したところ、そのままで大丈夫だと言われましたが結局腑に落ちないままになっています。
元のコードは載せることができないのですが、MSVCのstd::chrono::get_tzdb_listの実装を見ていてぱっと見同じようなことが行われているような気がしました。
それを参考に以下のようなプログラムを作成しました。
ソースコード
c++
1#include <iostream> 2#include <atomic> 3#include <chrono> 4 5struct A 6{ 7 A() { std::cout << "Created" << std::endl; } 8 ~A() { std::cout << "Destroyed" << std::endl; } 9}; 10 11inline std::atomic<A*> g_a; 12 13inline A& get_a() 14{ 15 auto a_ptr = g_a.load(); 16 if (a_ptr != nullptr) 17 return *a_ptr; 18 19 auto my_a = static_cast<A*>(std::calloc(1, sizeof(A))); 20 if (my_a == nullptr) 21 throw std::runtime_error("bad alloc"); 22 23 try 24 { 25 std::construct_at(my_a); 26 } 27 catch (const std::runtime_error&) 28 { 29 std::free(my_a); 30 throw; 31 } 32 catch (const std::exception& e) 33 { 34 std::free(my_a); 35 throw std::runtime_error(e.what()); 36 } 37 38 if (g_a.compare_exchange_strong(a_ptr, my_a)) 39 { 40 a_ptr = my_a; 41 } 42 else 43 { 44 std::destroy_at(my_a); 45 std::free(my_a); 46 } 47 48 return *my_a; 49} 50 51int main() 52{ 53 try 54 { 55 auto& tzdbl = get_a(); 56 } 57 catch (std::exception& e) 58 { 59 std::cerr << e.what() << '\n'; 60 } 61 62 return 0; 63}
出力
Created D:\Lab\Repos\Test\x64\Debug\Test.exe (プロセス 39856) は、コード 0 で終了しました。 このウィンドウを閉じるには、任意のキーを押してください...
知りたいこと
出力からもわかる通りメモリは解放されていない?(デストラクタが呼ばれていない)ことがわかりました。そのため、結局なぜメモリを開放しなくてもいいのかわかりませんでした。
以上を踏まえて、
- なぜ解放しないで大丈夫と言われたのか
- そもそもソースコードはおかしくないか
- 根本から勘違いしてることはないか
の3点についてご教示いただけると幸いです。
補足情報(FW/ツールのバージョンなど)
実行環境: Windows10 Visual Studio 2022 ver17.5.3(/std:c++20)





回答1件
あなたの回答
tips
プレビュー