お世話になります。
現在、Visual Studio 2005にてMFCのC++のプログラムを作成しているのですが、そこでメモリの使用容量について疑問に感じた点があったのでこちらで、質問させて頂きました。

お聞きしたい内容は
あるクラス1内で別のクラス2を宣言する際に、メンバ変数としてそのクラス2を宣言し、クラス1のコンストラクタでnewでメモリを確保し、デスクリタでdeleteする方法と、その都度クラス2の変数または関数が必要なときにnewでメモリを確保して、deleteで開放する方法とでは、メモリの確保等で違いがなにかありますでしょうか?
また、クラス2をクラス1,クラス3で使用する場合には、クラス1,クラス3でそれぞれクラス2のオブジェクトを宣言するのと、クラス1でクラス2のオブジェクトを宣言し、そのオブジェクトをクラス3でexternするのではどちらの方がメモリの使用等からよい方法なのでしょうか?
今までほとんどメモリを気にせずにプログラムを作っていた為、メモリの使用の点ではほとんど無知な為、変な質問なのかもしれませんが、ご存知の方がいらっしゃいましたら、ご回答をお願い致します。

開発環境は
Widows CE 6.0
Visual Studio 2005
です。

A 回答 (3件)

その都度、オブジェクトを生成して済むのであれば、静的メンバ関数にできないか検討してみてはどうでしょうか?


静的メンバ関数にできるのであれば、オブジェクトを生成する必要がなくなりますから、メモリの使用量はゼロになります。
    • good
    • 0
この回答へのお礼

その都度クラス1,クラス3で呼ばれるクラス2の関数を静的関数にしてみたらいい、ということでしょうか?
そうすれば、確かにメモリの使用はなくなりますよね。
その方法で考えてみます!!

お礼日時:2009/05/25 18:26

>どちらの方がメモリの使用等からよい方法なのでしょうか?



"等"という言葉があったのでツッコミを入れさせていただきます。
メモリの使用だけに限定されないと解釈しています。

まず、何度も何度もnewを繰り返すと”メモリの断片化(フラグメント)"が
起きる恐れがあります。

http://yougo.ascii.jp/caltar/%E3%83%95%E3%83%A9% …

最近のPCであればメモリを十分に積んでいるので
1) 1MByte new
2) 1MByte delete
3) 100kByte new
4) 100kByte delete
5)1MByte new
6)1Mbyte delete
をするよりは
最初から1MByteをnewもしくはstaticで確保して、使いまわすほうが
好ましいと思われます。
もちろん3)と4)の間では900kByteも無駄が生じることは
百も承知ですが
2GByteの物理メモリで900kByte気にしてもしゃーない
という”富豪プログラミング"です。

あと
>クラス1のコンストラクタでnewでメモリを確保し、デスクリタでdeleteする方法

この場合、クラス1にクラス2の"ポインタ"をもつということになりますね

>クラス1,クラス3でそれぞれクラス2のオブジェクトを宣言する
この場合、クラス2のオブジェクトをクラス1(および3)が抱え込む形ですね。

この2つのパターンにはメモリ以外に重要な違いがあります。
それは前者(ポインタ)の場合は"前方宣言"で済ますことが可能ということです。

前方宣言を使うと、クラス1のコンパイルにクラス2の情報は不要になります。
クラス2の実装を変更してもクラス1はコンパイルしなおさなくて済みます。
ことは、ビルド時間の長短の問題だけではありません。

クラス2はクラス1に影響を与えず、まったく自由に変更できるということは
クラス2はそれと機能面で互換性のある2aや2b...と自由に交換可能に
なるのです。
これは、複雑なプログラムを組む時に非常に大きなメリットとなります。

以上、メモリの瞬間・瞬間の利用効率以外の
長期的視点からみてみました。

以上の視点とメモリを極力無駄にしない努力を
時には天秤にかけ
どちらを優先するか判断してみてください。
    • good
    • 0
この回答へのお礼

丁寧なご回答ありがとうございます。
メモリのnewとdeleteを繰り返すと、フラグメントが発生するのですか。。それは初めて聞きました、参考にさせて頂きます。
ということは、その都度のメモリの使用のみを考えて、あるクラスの各関数内で、ローカル変数として、別のクラスのオブジェクトのnew.deleteを繰り返してメモリを確保するよりも、長期的にみてあるクラスのグローバル変数として他のクラスのオブジェクトを宣言し、コンストラクタでnew,デストラクタでdelteした方がよいとも考えられるということですね。

また、教えて頂いたクラスのオブジェクトの前者、後者の違いですが、あるクラスで別のクラスのオブジェクトを宣言するときは、ポインタとして呼び出す方が、利便性があるということですね。

ご回答ありがとうございます。

お礼日時:2009/05/27 09:00

クラスのインスタンスがメモリー上に実在するのは


クラスのコンストラクタが実行されてインスタンス
が生成されてから、そのインスタンスがデストラクタで
破棄されるまでで、これをクラスの寿命といいます。
つまり生きているクラスは全てメモリ上に存在するわけです。

以上の理屈より、ご質問の件は自明ですね(^^)/。
    • good
    • 0
この回答へのお礼

ということはクラス1のメンバ変数にクラス2のインスタンスを指定し、クラス1のコンストラクタでnewでメモリを確保すると、クラス1のデストラクタが呼ばれるまで常にクラス2のインスタンス分のメモリが確保され続けてしまうということですね?
逆に、その都度new,deleteを呼ぶことでインスタンス分のメモリの確保・開放を繰り返しているということですか。

だとしたら、面倒でも何度も繰り返しインスタンスを作成したほうがメモリの面ではいいということですね。

お礼日時:2009/05/25 18:23

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q自クラスをnewしたインスタンスの参照

また、よろしくおねがいします。
あるインスンタンス(A)から別のクラスをnewしてインスタンス(B)を作成し

class A{
public A(){}
B b = new B();
public hoge(){
System.out.plintln("hoge");
}
}

class B{
public B(){}
A.hoge(); <<= ここから自クラスをnewしたAのhoge()を起動させたい
}

こんな風にnewされたB側からAのメソッドを動かしたいなんて場合は、どのようにするんでしょうか?

Aベストアンサー

もう一つ別の方法として、class Bをclass Aの内部クラスにしてしまうという方法があります。

class A {
class B {
public B() {}
void x() {
A.this.hoge(); // 内部クラスBのインスタンスからAのインスタンスメソッドを呼ぶ書き方
}
}
Aの実装以下略
}

QVisual Studio .net ヘッダーファイルに付加されている宣言について

お世話になっております.
現在Visual studio .net 2003で書かれたシステムのソースを読んでいるのですが,ヘッダファイルの冒頭に

#if !defined(AFX_ ...

というものがあります.
私がファイルを新規作成しても追加されないのですが,これは何かウィザードを用いてヘッダファイルを生成したときに付加されるものなのでしょうか?

...の部分には16進数が記載されています.
よろしくお願いいたします.

Aベストアンサー

おそらくですが・・・

#pragma onceがサポートされたのはどうもVC5.0からのようで、それ以前のバージョンのソースとの互換のために、質問のマクロをつける動作をしていたんだと思います。
で、.Netになってから大幅に動作変更があったので、ついでにウィザードの動作も変更したのかと・・・

Q基本クラスポインタ = new 派生クラス[i];

基本クラスのポインタ変数pbaseを宣言し、new演算子にて派生クラスの配列を動的に確保して、pbaseに代入した場合、delete[] pbaseは上手く動作するのでしょうか。
(Aのデストラクタは仮想関数にしてあるとしておきます)

------ex-start------
class A {};
class b:public A{};

main()
{
  A * pbase
  pbase = new B[5];
  delete[] pbase
}
------ex-end------

例えば、
class Aは12バイト
class Bは20バイト
である場合、配列のサイズが違うのに、delete[]でちゃんと開放されるのでしょうか。
それともnew/deleteは確保したサイズをシンボル毎に記憶しているのでしょうか。
どうもこの辺が曖昧で実装する時にあやふやになってしまいます。どなたかお知恵をお貸しくださいませ。

Aベストアンサー

struct A { int x; virtual ~A() { cout << "~A: " << this << endl; } };
struct B: A { int y; ~B() { cout << "~B: " << this << endl; } };
B *b = new B[5];
A *a = b;
A *a2= a + 2;
a2->x = 1;
delete[] a;
これを素朴に考えると a2 は単純に a に 2 * sizeof(A) バイト足した場所(b[1] と b[2] の中間ぐらい?)を指すかもしれないです。a2->x = 1 は危険な感じがします。
delete [] が、配列の各要素のデストラクタに渡す this を求めるときに同様の失敗をするかもしれないです。

…と今日まで思っていましたが、実際やってみると delete[] で new B[5] が削除できてしまいました(VC++6.0)。不思議です。

Qmalloc、new のメモリ確保について

mallocで確保できる最大メモリ領域と
newで確保できる最大メモリ領域を知りたいです。

ご存知の方、教えて下さい。

Aベストアンサー

> malocで確保出来る最大メモリ領域は決まっていない
> と言うことで宜しいのでしょうか。

決まっていないのではなく、知る方法がないのです。
実装によっては、決まっていない(そのときどきの状況による)場合もあると思います。

> new演算子で、charの配列のメモリ領域を確保しようとする場合
>
> char * buff;
> buff = new char[100000];
>
> も同様に、確保できるメモリ領域は決まっていない
のでしょうか?

この場合、割付けに成功すれば、少なくとも100000バイトを確保できるだけです。実際にどれだけ確保したのか、あるいは同様の割付けをどれだけ行えるかを知る一般的な方法はありません。

Qクラスの参照(同じファイル内 vs 別々のファイルの場合)

二つの.javaファイルがあります。
<ABC.java>
class ABC {
public static void main(String args[]) {
A obj = new A();
obj.hello();
}
}
---------------------------------------------

<A.java>
class A{
void hello() {
System.out.println("Hello from A");
}
}
---------------------------------------------
ABC.javaファイルでコンパイルすると、「 シンボルを解釈処理できません。」というエラーメッセージが出ます。でも、ABC.javaファイルの中に、class Aを続けて書くとコンパイルできます。なぜ、別々のファイルにすると参照できないのでしょうか?
(おなじフォルダ内に入れています)
教えてください。よろしくお願いします。

二つの.javaファイルがあります。
<ABC.java>
class ABC {
public static void main(String args[]) {
A obj = new A();
obj.hello();
}
}
---------------------------------------------

<A.java>
class A{
void hello() {
System.out.println("Hello from A");
}
}
---------------------------------------------
ABC.javaファイルでコンパイルすると、「 シンボルを解釈処理できません。」というエラーメッセージが出ます。でも、ABC.javaファイルの中に、class A...続きを読む

Aベストアンサー

おはようございます。

質問内容と、他の方の解答の補足の書き込みをみて
思ったのですが、ソースファイルとクラスファイル
を勘違いしてませんでしょうか?もしかしたら、
必要以上に解答内容が大きくなってしまって混乱
してるのかな?

実際解答としては「No#1」の方の内容で十分です。

簡単に説明しますと…
2つのクラスを同一Javaファイルに書いてコンパイル
すると、両方のクラスのクラスファイルが生成されます。
しかし2つのクラスを別々のファイルに書くと,当たり前
ですが、それぞれのクラスファイルしか生成されません。

質問内容のテストプログラムでは、Aクラスを記述している
ファイルをコンパイルしないで、ABCファイルをコンパイル
したのではないですか?それなら、Aクラスが存在していな
いのですから、コンパイラもわからないので「シンボルを
解釈処理できない」というエラーを出してしまいます。

ちょっと長くなってしまいましたね^^;

Qnew と malloc によるメモリの動的確保について

初めて投稿させて頂きます。よろしくお願い致します。
現在、以下のような、2次元配列による動的なメモリの確保を意図して、コードをC/C++にて記述しています。
(コンパイラはMINGW32のg++ 3.4.5)

//mallocによるメモリ動的確保
data = (char **)malloc(num * sizeof(char*));
for(i=0; i<rowNum; i++){
data[i] = (char *)malloc(sizeof(char)*256);
}

//newによるメモリ動的確保
data = new char*[rowNum];
for(i=0; i<rowNum; i++){
data[i] = new char;
}

C++で書くのならば、
「mallocによるメモリ確保は辞め、newによるメモリ確保をしなさい」
という指摘が、書籍でもwebでもありましたので、
両方書き、両者を比べているのですが、理由がイマイチ分かりません。

10万行ほどのテキストデータで実験させてみたのですが、
mallocによる記述の方が、動作が数秒速いようなのです。

それで、new やmalloc で実際何をやっているのか、コードを見ようと思ったのですが、

newでは、

void* operator new(std::size_t) throw (std::bad_alloc);
void* operator new[](std::size_t) throw (std::bad_alloc);
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

というnewファイルの記述で行き詰まり、

malloc は malloc_allocator.hというファイルで行き詰りました。

以上を踏まえて、
1)そもそも、上記のメモリ動的確保記述はスマートな書き方なのか
2)実際に、newやmallocは、どういった手法でメモリ領域を確保しているのか

以上の2点について、ご教授下さい。よろしくお願い致します。

初めて投稿させて頂きます。よろしくお願い致します。
現在、以下のような、2次元配列による動的なメモリの確保を意図して、コードをC/C++にて記述しています。
(コンパイラはMINGW32のg++ 3.4.5)

//mallocによるメモリ動的確保
data = (char **)malloc(num * sizeof(char*));
for(i=0; i<rowNum; i++){
data[i] = (char *)malloc(sizeof(char)*256);
}

//newによるメモリ動的確保
data = new char*[rowNum];
for(i=0; i<rowNum; i++){
data[i] = new char;
}

C++で書くのならば、
「malloc...続きを読む

Aベストアンサー

まあ, operator new[] は operator delete[] のための管理情報を追加しなきゃならないのでどうしても malloc より遅くなる (少なくとも「速くなることだけはない」) んですけどね....
どうしても速度が欲しいなら malloc, お手軽を求めるなら std::vector を使うのが普通かな. ああ, 今どき 3.4.5 もどうかと思うので 4.3.3 なり 4.4.2 にするってのも考えるべきかと.

Qnew クラス名(Activity名.this);

Android

・下記のようなコードがあるのですが、このとき「.this」の意味を教えてください
・Activityクラス自身?
・「.」で繋いでいる意味も、「this」の意味も良く分かりません
・thisだけでは駄目?
・引数は1つ?

public class Hoge extends Activity {

 public class C1 {//インナークラス?

  protected m1method(略) {
  略 = new クラス名(Hoge.this);

Aベストアンサー

このソースはHogeクラスの中に新しくC1クラスを定義しているのでC1はHogeクラスの
インナークラスで間違いなく Hode.C1 と「.」でつないで表記します。

このときのHoge.thisとは、Hoge.C1クラスのオブジェクト自身のことです。例えば、
tmp = new Hoge.C1(); とした場合は tmp に該当します。

また、最後の行は、自分自身をパラメータとして「クラス名」のオブジェクトを生成
していますので、引数の数はそのクラスによります。

試してないので不確かですが、thisだけだとHogeクラスのオブジェクトと間違う
可能性がありますので、Hoge.thisのほうが確実です。

Qクラスメンバをnewで宣言できますか?

こんにちは。
教えていただきたいのですが、クラスメンバ(変数)を動的に確保することは
できるのでしょうか?(一応やってみたのですが、エラーになってしまいました。)
それから、Newでの二次元配列の確保は、どうやったらよいのでしょうか?
ヘルプでもうまく探せません。
よろしくお願いします。

Aベストアンサー

ポインタをクラスメンバにしておいて、
newが返すポインタをそこに入れる、
というのでだめですか?

class Integers {
 public:
  Integers() : ip(0) { }
  ~Integers() { if( ip != 0 ) delete[] ip; }

  allocate(int n){ ip = new int[n]; }

 private:
  int *ip;
};


2次元配列の確保は、こんな感じでどうでしょう?

int (*twodim)[CNUM]
 = reinterpret_cast<int (*)[CNUM]>(new int [CNUM * RNUM]);

CNUMとRNUMは列数、行数を表す定数です。
CNUM*RNUM個のintを確保して、
CNUM個のintをひとまとめにして指すポインタに
castして代入しています。

これで、twodim[1]は2行目のint配列の先頭を指すポインタになるので、
twodim[1][2]で、2行目の第3列目の要素を指します。

ポインタをクラスメンバにしておいて、
newが返すポインタをそこに入れる、
というのでだめですか?

class Integers {
 public:
  Integers() : ip(0) { }
  ~Integers() { if( ip != 0 ) delete[] ip; }

  allocate(int n){ ip = new int[n]; }

 private:
  int *ip;
};


2次元配列の確保は、こんな感じでどうでしょう?

int (*twodim)[CNUM]
 = reinterpret_cast<int (*)[CNUM]>(new int [CNUM * RNUM]);

CNUMとRNUMは列数、行数を表す定数です。
CNUM*RNUM個のintを...続きを読む

Q動的に変数をセット後他クラスから参照する場合

コンストラクタで変数にセットした後
他のクラスでインスタンスを生成することなく
セットした変数を参照したいのですが、
staticにすると、他クラスで変数を変更することも
できてしまいます。他の方法がありますでしょうか?
変数はprivateにして、getterで取得するという方法も
考えられますが、static finalな変数として扱う方法が
あるか、お分かりの方いらっしゃいましたら教えてください。

Javaを初めて1ヶ月なので、見当違いの質問でしたらご指摘ください。

例)
Class A{
 static final String aaa;
A(String paraStr){
aaa = paraStr;
}
}

Class B{
static void main(String[] args){
new A("test");
}
}

Class C{
void chStr(){
System.out.println(A.aaa);
A.aaa = "changeStr"
System.out.println(A.aaa);
}
}

期待する値
test
test

もしくは、実行時にfinalの値は変更できない等のException

宜しくお願いします。

コンストラクタで変数にセットした後
他のクラスでインスタンスを生成することなく
セットした変数を参照したいのですが、
staticにすると、他クラスで変数を変更することも
できてしまいます。他の方法がありますでしょうか?
変数はprivateにして、getterで取得するという方法も
考えられますが、static finalな変数として扱う方法が
あるか、お分かりの方いらっしゃいましたら教えてください。

Javaを初めて1ヶ月なので、見当違いの質問でしたらご指摘ください。

例)
Class A{
 static final...続きを読む

Aベストアンサー

static finalな変数
は、コンストラクタを使わなくても使用できなければいけませんから
質問文のようにそのクラスのコンストラクタからであっても、既に変更はできません。

Qvisual c++ CMapWordToObでクラスオブジェクトの格納

visual c++を最近はじめたのですが、うまくいかなくて困っています。

1.自作クラス
class myObj : CObject
{

private:
CString mstrIpAdd;
CString mstrNetAdd;
CString mstrFilePathAdd;

public:
myObj();

//プロパティ設定
void setIpAdd(CString value);
void setNetAdd(CString value);
void setFilePathAdd(CString value);

CString getIpAdd();
CString getNetAdd();
CString getFilePathAdd();

virtual ~myObj();
:
:
:
------------------------------------------

フォームでボタンを押すと実行する部分

myObj objMy;
CMapWordToOb objMap;

 for(i = 0; i < 1 ; i++){
  objMy.setIpAdd(edit);
  objMy.setNetAdd(combo);
  objMap.SetAt(i,objMy);
 }

CMapWordToObに自分で作成したobjMyクラスを入れたいのですが、エラーが帰ってきます。

<エラー内容>
error C2664: 'SetAt' : 2 番目の引数を 'class myObj' から 'class CObject *' に変換できません。 (新しい機能 ; ヘルプを参照)
この変換を実行可能なユーザー定義変換演算子がないか、または演算子を呼び出せません。


フォームで取得した値を、objMyクラスに挿入し、そのクラスをMapオブジェクトに挿入しているのですが、うまくいきません。 (^^;
すみませんが対処方法を教えてくださいませ。よろしくお願いします。

文字数制限で全体のソースを入力できないため一部を表示しています。

visual c++を最近はじめたのですが、うまくいかなくて困っています。

1.自作クラス
class myObj : CObject
{

private:
CString mstrIpAdd;
CString mstrNetAdd;
CString mstrFilePathAdd;

public:
myObj();

//プロパティ設定
void setIpAdd(CString value);
void setNetAdd(CString value);
void setFilePathAdd(CString value);

CString getIpAdd();
CString getNetAdd();
CString getFilePathAdd();

virtual ~myObj();
:
:
:
-------------------------...続きを読む

Aベストアンサー

'うまくいかない'/'エラーになる'を説明してください。
- なにがどううまくいかないのですか?
- なにをするとどんなエラーになるのですか?

さらに、

- マニュアル/ドキュメントを読んでいますか?
- 行き当たりばったりにコードを書いて悩んでいませんか?

-> こんな感じでしょうか?
違います。
コレクションに格納する「要素」はちゃんとnewしたものですか?


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング