質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

10181閲覧

new の使いかた

samamoto1205

総合スコア20

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/03/07 12:22

現在、ゲームプログラミングの勉強をしているものです。
c++以外はあまり勉強できていない為c++での回答をお願いします。
メモリの動的確保の利便性、というか使い道のようなものについての質問です。

現在、私のメモリ動的確保の使いかたの認識として、


1.グローバル変数などでクラスのポインタを作成し、メイン関数などの中でクラスをnewでメモリ確保、プログラムの最後でまとめてdeleteで解放する(Init関数などを作らず、コンストラクタ、デストラクタによって初期化や解放忘れを防ぐため)
2.必要な配列の個数がプログラム中で変動する可能性があるときに、newで動的確保する


この2種類が基本的なものだと認識しております。
しかし、どちらの使い方も私の中ではあまりはっきりしておりません。というか、「あまり使い道がない」な、と思ってしまいます。正直どちらもnewを使わずとも可能なので、少なくとも使わなければいけないもの、ではないとは思っています。

少し極端な例になりますが、「初期化、解放忘れが絶対にない」「配列は使わないor全て静的確保で問題ない」を前提にした場合、もしかしてメモリの動的確保自体必要ないものなのでしょうか。

お尋ねしたいのは、


1.c++でnewに上記以外の使いかたがあるのか
2.「初期化、解放忘れが絶対にない」「配列は使わないor全て静的確保で問題ない」事が確定しているとき、newは必要ないものなのか


ということです。
拙い文章ではありますが、どうかよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

現在、私のメモリ動的確保の使いかたの認識として、
1.グローバル変数などでクラスのポインタを作成し、メイン関数などの中でクラスをnewでメモリ確保、プログラムの最後でまとめてdeleteで解放する(Init関数などを作らず、コンストラクタ、デストラクタによって初期化や解放忘れを防ぐため)
2.必要な配列の個数がプログラム中で変動する可能性があるときに、newで動的確保する

動的メモリ確保を必要とするのは、本質的には「プログラムのコンパイル時点ではその動作に必要なメモリ量を決定できない」からです。質問文中にある2は正しい認識ですが、1には必然性がありません(あなたの認識が間違っているという意味ではなく、動的メモリ確保を伴わないグローバルオブジェクトという設計方法もあり得るという解釈)。


初期化はコンストラクタで行うことが多いです。(中略)
最後に、配列も含めて全て静的確保で良いケースならnewは使わなくても問題ないです。

上記の認識で正しいです。そして、C++プログラムとしては「動的メモリ確保を必要としないならば、全てを静的メモリ確保とする方が望ましい」です。あらゆる動的メモリ確保処理はバグ要因となるリスクがありますし、実行時パフォーマンス(処理時間・メモリ効率)の点でも静的メモリ確保の方が優れています。

理想的には上記の通りですが、現実には多くのプログラムで取扱データ量やユーザ入力をコンパイル時に確定することは出来ません。このため、プログラム実行時の動的メモリ確保は避けられない(ことが大半)です。


1.c++でnewに上記以外の使いかたがあるのか

簡単な答え:newは動的メモリ確保のための仕組みです。それ以上の使い方はありません。

マニアックな答え:極一部のC++ライブラリでは、placement-new構文とよばれる特殊な呼び出し方を利用し、演算子オーバーロードにより動的メモリ確保以外の役割を担うことがあります。(私が知る限りはIntel TBB

2.「初期化、解放忘れが絶対にない」「配列は使わないor全て静的確保で問題ない」事が確定しているとき、newは必要ないものなのか

動的メモリ確保を行う合理的理由が無ければ、newは必要ありませんし使うべきでもありません。

投稿2017/03/08 05:27

編集2017/03/08 07:54
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

samamoto1205

2017/03/08 07:34

なるほど、やはり動的確保である必要がないならnewする意味はないですね。。。 演算子オーバーロードという使い方もありましたか。しかしこちらは特殊みたいなので少なくとも今の自分には関係ないですね。。。
guest

0

こんにちは。

1.c++でnewに上記以外の使いかたがあるのか

「上記の使い方」の範囲がイマイチはっきりしませんが、たぶん色々あります。
多くはメンバ変数としてのポインタ変数で保持するケースと思います。

2.「初期化、解放忘れが絶対にない」「配列は使わないor全て静的確保で問題ない」事が確定しているとき、newは必要ないものなのか

初期化はコンストラクタで行うことが多いです。コンストラクタはnewでも呼ばれますが、静的確保した場合でも呼ばれます。
newしたあとのdelete忘れが解放忘れです。newしなければ解放忘れれはないですよ。初期化の反対の終了処理はデストラクタで行われます。静的確保した時でもオブジェクトが破棄される時にデストラクタは呼ばれます。
最後に、配列も含めて全て静的確保で良いケースならnewは使わなくても問題ないです。

処理データ量が少ない時はメモリを少ししか使わず、データ量が多い時は多量のメモリを使いたいような時はたいへん良く有ります。その時、newやmalloc等が大活躍します。
newもmallocも使わなかったとすると、グローバル変数やローカル変数等の事実上の固定長メモリを使うしか無いので、データ量に合わせてリビルドする必要があります。(ローカル変数は多少融通は効きますが、この目的には事実上使えません。)

投稿2017/03/07 13:04

編集2017/03/07 13:06
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

samamoto1205

2017/03/07 15:37

>「上記の使い方」の範囲がイマイチはっきりしませんが、たぶん色々あります。 多くはメンバ変数としてのポインタ変数で保持するケースと思います。 クラス内に保持したポインタ変数をコンストラクタかどこかでnewする、ということでしょうか? 動的確保するメリットのある使い方ってなにがあるかな、という意味の質問でした。伝わりにくい文章で申し訳ありません。 >処理データ量が少ない時はメモリを少ししか使わず、データ量が多い時は多量のメモリを使いたいような時はたいへん良く有ります。その時、newやmalloc等が大活躍します。 変数のメモリを可変長で持つやつでしょうか?なるほど、失念していました。その使い方がありましたね。 >最後に、配列も含めて全て静的確保で良いケースならnewは使わなくても問題ないです。 やはりすべて静的確保でよい場合はnewは必要ないのですね。。。 「newとかdeleteとか使うとなんかプロっぽい!」みたいな理由で、クラスそのもののポインタ変数をグローバル変数として保持して、メイン関数の最初でnew、一番最後にdelete みたいな使い方をしていたのですが、やはりこの使い方って少なくとも動的確保する意味はないですよねσ^_^; それとも、「コンストラクタとデストラクタに初期化と解放は任せる」ためのこの使い方はコーディングとしてありなのでしょうか?
Chironian

2017/03/07 16:09

> 「newとかdeleteとか使うとなんかプロっぽい!」 気持ちは分かりますけど、それはプロの態度ではないですよ。 何が適切か検討して、適切な機能を使うのがプロですね。 > 「コンストラクタとデストラクタに初期化と解放は任せる」 う~ん、少し勘違いがあるようです。 コンストラクタは初期化、デストラクタは後始末をします。 その中でそのクラスが使うメモリ等のリソースの獲得と解放を行うことも有ります。 しかし、そのクラスのインスタンスそのもののメモリの獲得や解放はしません。 class Foo {int x; int y;}; がある時、xやyの領域の獲得や解放はFooのコンストラクタやデストラクタの役割ではないのです。 int main() { Foo foo; ... return 0; } とするとスタック上にFooのインスタンス領域fooが獲得され(これがx, yの領域が獲得されるという意味です)、コンストラクタが呼び出されます。 main()関数から抜ける時、Fooのデストラクタが自動的に呼び出され、その後Fooの領域がスタック上から解放されます。 Foo* foo=new Foo;にてヒープ上にFooのインスタンス領域が獲得され、Fooのコンストラクタが呼び出されます。次にそのアドレスがポインタ変数fooに設定されます。 delete foo;すると、Fooのデストラクタが呼び出され、次にfooのメモリがヒープ上で解放されます。
samamoto1205

2017/03/08 07:47

コンストラクタ、デストラクタはインスタンス内のメンバ変数などの初期化をすることができるというだけであり、インスタンスそのものを生成、解放しているわけではない、ということですね。 きちんと理解できていませんでした、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問