はじめまして。
C++のライブラリ(静的、動的問わず)について
いくつか教えてください。

たとえば、1つのクラスで定義した以下のようなライブラリ
(まずは、静的 or 動的は問いません)があるとします。
class library
{
library();
~library();
public
GetX();
private
 int a;
}

さらに、実行プログラムMain.exeが存在し、このMain.exeは、
上記ライブラリをリンクしているものとします。

このとき、Main.exe内では、libraryをnewすることもなく、
library::GetX();と呼べるわけですが、

(1)コンストラクタはいつ呼ばれているのでしょうか?
(2)(1)に関係しそうですが、Main.exeがマルチスレッドの場合に、
   Main threadとsub threadから呼ぶときに、ライブラリのコンテキスト?インスタンス?は
   同じなのでしょうか?それともスレッドごとに作られるのでしょうか?

ご存知のかたいらっしゃいましたら教えてください。
説明不足があればご指摘ください。宜しくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

>こちらですが、高度なというのはどういう意味でしょうか?


>linux環境でもプロセス間では割り当てメモリが
>異なるような気がいたしますが、
>もし開発環境で異なるということは、
>実際に、開発を始める場合にこのあたりについては
>OSを調べればよいのでしょうか?

基本的にOSの問題ととらえてよいと考えます。
今あるPC用のOSであれば、Win/Linux/Free BSDなど
は皆"高度"であると考えてよいと思います。

組み込み用途だと、直接物理アドレスにアクセスすることも
多いですよね。
むしろ、PCのように論理アドレスが割り振られるほうが
珍しいのでは?
という感じです。
    • good
    • 0
この回答へのお礼

何度もお答えいただきありがとうございます。

直接物理アドレスにアクセスするような場合には、
また変わってくるということですね。
だいぶ理解が深まりました。

お礼日時:2009/05/26 20:24

>static関数はstatic関数だけしか呼べないというのも合っていますでしょうか?



厳密にいうと違いますね。
クラスメンバ関数限定での話であれば
staticメンバ関数は非staticメンバ関数を呼べないので、
static関数しか呼べないという言い方もできます。

ただし、static関数でもクラスに所属しない関数は自由に呼べます。
その意味で、厳密にはクラスのstatic関数は、クラスのstatic関数
しか呼べないわけではありません。

>class内で定義したstatic関数(library::GetX();)とグローバル関数は
>単に名前が違うものと思えばよいのでしょうか?

基本的な扱い方は、クラス名::をつけられたグローバル関数と
考えてもよいと思います。
ただし、あくまでもクラスに所属する以上
アクセス制限(public, protected, private)からは逃れられません。

publicなstaticメンバ関数は
(呼び出す側からすれば)
クラス::をつけて呼ぶことがお約束のグローバル関数と考えてよいと思います。

>たとえば、プロセスA、Bがあり、Aのほうで定義(合っていますか?)した
>static関数Aがあった場合、
>プロセスBからstatic関数Aは呼べるのでしょうか?

また、理解に苦しむのですが....
そもそも、プロセスAとプロセスBはお互い関数コールなどは
”基本的には"できません。
プロセス間通信など、特別な手法が必要です。

私が勝手に想像するに
複数のプロセス間でクラスstatic関数を通じてクラスのメンバ変数を
共有できるのか?

ということがお知りになりたいのではと思います。

具体的にコードを提示しましょう

class c
{
protected:
static int m_Count = 0;
public:
static void Inc() {m_Count++;}
static int GetCount() {return m_Count;}
}

こんなクラス cがあります。
プロセスX内で
c::Inc();
と実行した後
c::GetCount()は1を戻します。
これ以後
プロセスXではc::Inc()を一切呼ばないものとします。

その後、プロセスYで
c::GetCount()
を呼んだら、答えはどうなるか?

初期値のまま0が戻るのか、
それとも
プロセスXの実行結果を反映して
1が戻るのか?

こういうことではないでしょうか?

答えは前者(0)です。
クラスのstaticメンバであっても
プロセス境界を越えて共有することはできません。

ちょっと低レベル(マシン寄りという意味)な話をさせてもらうと
プロセスにはそれぞれ、別々のメモリが割り当てられ、
お互いに、他のプロセスのメモリをアクセスすることは
不可能です。

プロセスXでいうアドレス0x00001234は
物理メモリの0xAAAA1234を指しているかも知れません。

プロセスYでアドレス0x00001234に書き込んでも
物理メモリの0xAAAA1234には(通常)書き込まれません。
なぜなら
プロセスYにはプロセスXが使用するメモリとは重ならない
領域が割り当てられるからです。
プロセスYの0x00001234は物理メモリの
0xBBBB1234
に割り当てられるかもしれません。

ソースコード上では
char* p;
p = 0x00001234;
というコードがプロセスX、Y両者にあれば
*pを通じて情報が共有できそうですが、
(実際、MSDOSなどの時代にはできていました)
Windowsのような”高度な"OSでは不可能です。

それにより
1つのプロセスが誤動作を起こしても
他のプロセスに影響が及ぶ可能性を
(0とはいかないが)低減させているのです。

この回答への補足

とても分かりやすいご説明ありがとうございます。

> 私が勝手に想像するに
> 複数のプロセス間でクラスstatic関数を通じてクラスのメンバ変数を
> 共有できるのか?

こちら、そのとおりです。
クラスstatic関数だけでなく、グローバル関数についても
お聞きしたかったところですが、
プロセス間ではスレッド間とは異なり割り当てられているメモリが
異なるということでアクセスすることはできないということだと思います。

> ソースコード上では
> char* p;
> p = 0x00001234;
> というコードがプロセスX、Y両者にあれば
> *pを通じて情報が共有できそうですが、
> (実際、MSDOSなどの時代にはできていました)
> Windowsのような”高度な"OSでは不可能です。

こちらですが、高度なというのはどういう意味でしょうか?
linux環境でもプロセス間では割り当てメモリが異なるような気がいたしますが、
もし開発環境で異なるということは、
実際に、開発を始める場合にこのあたりについてはOSを調べればよいのでしょうか?
それともプログラミング言語を調べるべきなのでしょうか?
それともコンパイルの設定などで変更できるものなのでしょうか?

補足日時:2009/05/23 11:52
    • good
    • 0

ライブラリとクラスの概念を混同していませんか?


この2つには全く何の関係もありません。
そこを明確にしましょう。

>1つのクラスで定義した以下のようなライブラリ

表現があやしいですが...
1つのクラスだけで構成されるライブラリ
と理解しておきます。

>上記ライブラリ
class library を含むライブラリ
と理解します。

>このとき、Main.exe内では、libraryをnewすることもなく、
>library::GetX();と呼べるわけですが、

えーーーーーーーーーーー
本当ですか?
基本的には無理です。
C++の言語仕様からいって不可能です。

GetX() がstaticなら可能ですが
staticじゃないですよね?

ライブラリでも一般のソースでもそうですが
クラス名::メンバ関数名
の形式でコールできるのは
1)派生クラス内部から基本クラスのメンバを呼ぶ場合
2)static関数を呼ぶ場合

に限定されます。

staticをつけ忘れたという前提で話します。
(違っていたらごめんなさい)

>(1)コンストラクタはいつ呼ばれているのでしょうか?

static関数を呼び出すのにオブジェクトは必要ありません。
(必要ないのでクラス名::の形式で呼べるのです)
コンストラクタが呼ばれなくても動作します。
その代わり、staticメンバ関数からはstaticメンバ変数にしか
アクセスできません。
staticでない”普通の"メンバ変数はオブジェクトが必要です。
(オブジェクト毎に違う値を取り得ます)
従って、オブジェクトの存在を前提としない
static関数からはアクセスできないのです。

>(2)(1)に関係しそうですが、Main.exeがマルチスレッドの場合に、
>   Main threadとsub threadから呼ぶときに、
>ライブラリのコンテキスト?インスタンス?は
>   同じなのでしょうか?それともスレッドごとに作られるのでしょうか?

先も述べたようにstatic関数にインスタンスは不要なのです。
これは、シングルスレッド、マルチスレッドとまったく違う次元の話です。
強いて言えば
マルチスレッドでもシングルスレッドでもインスタンスなしでアクセスできます。
staticメンバ関数が内部でstaticメンバ変数にアクセスしている場合
(よくあることです)
マルチスレッドの場合、排他をかけておかないと
正常動作しない可能性があります。

この回答への補足

ご指摘いただいたとおりstaticではないといけないですね。
説明不足のところいろいろお察しいただき感謝しております。

> static関数を呼び出すのにオブジェクトは必要ありません。
>(必要ないのでクラス名::の形式で呼べるのです)
> コンストラクタが呼ばれなくても動作します。

こちらですが、
static関数はstatic関数だけしか呼べないというのも合っていますでしょうか?
ちょっとstatic関数の理解ができていないかもしれません。
class内で定義したstatic関数(library::GetX();)とグローバル関数は
単に名前が違うものと思えばよいのでしょうか?

> 強いて言えば
> マルチスレッドでもシングルスレッドでもインスタンスなしでアクセ> スできます。

マルチスレッドではプロセス内の同じstatic関数を
どちらのスレッドからも実行できるということですね。

> staticメンバ関数が内部でstaticメンバ変数にアクセスしている場合
> (よくあることです)
> マルチスレッドの場合、排他をかけておかないと
> 正常動作しない可能性があります。

staticなものはそのプロセス単位?でただひとつしか存在しない、
存在することができないということだと思いますが、
異なるプロセス間ではどうなのでしょうか?
たとえば、プロセスA、Bがあり、Aのほうで定義(合っていますか?)した
static関数Aがあった場合、
プロセスBからstatic関数Aは呼べるのでしょうか?
もしくは、プロセスBで定義したstatic関数Bをstatic関数A内で
呼ぶことはできるのでしょうか?
よろしくおねがいします。

補足日時:2009/05/20 22:25
    • good
    • 0

> このとき、Main.exe内では、libraryをnewすることもなく、


> library::GetX();と呼べるわけですが、

staticじゃなきゃ呼べませんよ?

この回答への補足

ご指摘ありがとうございます。
staticでないと呼べないですね。

補足日時:2009/05/20 22:34
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

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

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

QC++変数宣言時のコンストラクタについて

Java開発をこれまでやってきたのですが、
C++を学ぼうとしています。
C++では下記のように宣言した場合hogeは
インスタンスになり、Hogeクラスのコンストラクタが呼ばれるようなのですが、
Hoge hoge;

Hogeクラスのコンストラクタが下記のような引数を持つものしか定義されていなかった場合は
どの様な振る舞いをするのでしょうか?
Hoge(int num);
Javaでは引数の有るコンストラクタしか宣言しなかった場合はデフォルトコンストラクタは
作られなかったと思うのですが、c++では引数のないデフォルトコンストラクタができてるのでしょうか?

また、デフォルトコンストラクタが出来ていなかった場合、
Hoge hoge;
というようにプリミティブ型のような変数宣言の仕方で引数有りのコンストラクタを呼ぶことは出来るのでしょうか?

Aベストアンサー

> Javaでは引数の有るコンストラクタしか宣言しなかった場合はデフォルトコンストラクタは
> 作られなかったと思うのですが、c++では引数のないデフォルトコンストラクタができてるのでしょうか?
Java と同じく、何らかのコンストラクタを定義してしまうとデフォルトコンストラクタは作られません。

> また、デフォルトコンストラクタが出来ていなかった場合、
> Hoge hoge;
> というようにプリミティブ型のような変数宣言の仕方で引数有りのコンストラクタを呼ぶことは
> 出来るのでしょうか?
Hoge hoge(10);
という具合に呼べます。
http://msdn.microsoft.com/ja-jp/library/s16xw1a8.aspx

あと、C++ では(引数なし)コンストラクタだけではなく、コピーコンストラクタ、デストラクタ、および代入演算子も定義しなければデフォルトのものが生成されるので注意してください。
http://docs.oracle.com/cd/E19205-01/820-1213/bkaht/index.html
http://tercel-tech.hatenablog.com/entry/2012/11/03/003302

> Javaでは引数の有るコンストラクタしか宣言しなかった場合はデフォルトコンストラクタは
> 作られなかったと思うのですが、c++では引数のないデフォルトコンストラクタができてるのでしょうか?
Java と同じく、何らかのコンストラクタを定義してしまうとデフォルトコンストラクタは作られません。

> また、デフォルトコンストラクタが出来ていなかった場合、
> Hoge hoge;
> というようにプリミティブ型のような変数宣言の仕方で引数有りのコンストラクタを呼ぶことは
> 出来るのでしょうか?
Hoge hoge(10);...続きを読む

Qint main()、void main()、void main(void)、int main(void)

今日、大学でC言語の講義の時間、先生が、

#include <stdio.h>

void main(void){

}

と宣言してプログラムを書くと教えていました。
main関数には、
main()
void main()
void main( void )
int main()
int main( void )

と、人によりいくつかの描き方があったりします。
どれが本当は正しいのでしょうか?
void mainはすべきではないとなんかの本で読んだのですが・・。

Aベストアンサー

通称C89という以前の言語規格(現行コンパイラの多くが準拠)では、下記のいずれかが正しい。
int main(int argc, char *argv[])
int main(void)

但し、最新のC言語規格(通称C99)では、
<ISO/IEC9899:1999>
or in some other implementation-defined manner.
</ISO/IEC9899:1999>
となっているので、処理系が戻り値のvoidを認めていればvoidも可。
# 組込み系などで戻り値を使わない環境もあるためでしょうか。

なので、コンパイラのマニュアルで戻り値のvoidにしていい/しろと書いてない限り、
voidは言語仕様的には正しくない。(でも動くものもある)

QC++/CLIの構造体のコンストラクタについて

C++/CLIの構造体のコンストラクタについて

C++/CLIで、固定サイズの配列を持つ構造体を、次のようにコーディングして使っています。


value struct AAA
{
public:
  array<unsigned short>^ m1;
  AAA(unsigned short dummy)
  {
    m1 = gcnew array<unsigned short>(4);
  }
};

AAA ^struct0 = gcnew AAA(0);


この方法で正常に動作するのですが、2点ほど気になる点があります。

(1) コンストラクタAAA(unsigned short dummy)を実装しなくても済む方法がないか?
(2) この方法では、struct0を、ネイティブヒープ領域に割り当てられない
(AAA *struct0 = new AAA(0))でコンパイルエラー)

(1)と(2)は関連する気もするのですが、これらを解決する方法はあるのでしょうか?

Aベストアンサー

>構造体をネイティブヒープ、マネージヒープのいずれにも割り当てることができれば、
言語仕様的に不可能です。
そもそもなんでそんなことが必要なんでしょうか?

C++/CLIでWin32APIを使うときはネイティブヒープ(スタックでも)の構造体でやり取りしますし。

Q【C++】静的リンクと動的リンクの違い

静的リンクと動的リンクの違いについて教えてください。

ググって、wikiにて確認したところ、
動的リンクは、実行時にプログラムの結合を行う。
静的リンクは、コンパイル直後の実行ファイル生成時に、ライブラリ等を全てリンクし、必要なコードが全て揃った実行ファイルを生成する。
というのはわかりました。

それを踏まえて、
 (1)-(1)libファイルで静的リンクさせるケース
  メソッドやプロパティのインデックスというかインタフェース仕様のみ書かれている。
  そして、そのインデックスを元にコンパイルチェックを行っている。

 (1)-(2)objファイルで静的リンクさせるケース
  objには、.cppと、.h に書かれている処理のうち、そのソース本体(そのクラス自身のモノとして持っている処理)のプロパティやメソッドのことが機械語で書かれている。
  プロパティやメソッドが書かれているため、当然インタフェース仕様もわかる。

であろうと捉えていますが、この認識で大雑把には合っていますでしょうか?

また、DLLを使う場合、動的リンクとは呼ばれているものの、
「DLLでは、objに加え、必要なリンクの情報まで持っている」と思われるので、
結局、リンカによるリンク実行時に、インタフェースで不整合が起きていないかはチェックされているという認識なのですが、合っていますでしょうか? 
(だとすると、なぜ、ある意味、DLLを使っていても静的リンクなのかなと感じ、動的リンクと呼ぶことに不自然さを感じます)

宜しくお願いいたします。
.

静的リンクと動的リンクの違いについて教えてください。

ググって、wikiにて確認したところ、
動的リンクは、実行時にプログラムの結合を行う。
静的リンクは、コンパイル直後の実行ファイル生成時に、ライブラリ等を全てリンクし、必要なコードが全て揃った実行ファイルを生成する。
というのはわかりました。

それを踏まえて、
 (1)-(1)libファイルで静的リンクさせるケース
  メソッドやプロパティのインデックスというかインタフェース仕様のみ書かれている。
  そして、そのインデックスを元にコンパ...続きを読む

Aベストアンサー

 (1)-(1)libファイルで静的リンクさせるケース
 (1)-(2)objファイルで静的リンクさせるケース

この2つは大体同じ意味です

[exe ファイル ]
obj を集めて作成します。
main関数が含まれているため、実行すると動作します。
exe ファイルを作成する際、実行されない関数等は含めません

[lib ファイル ]
obj を集めて作成します。
main関数が無い為、実行する事はできません。
当然全ての関数が lib ファイルに含まれます


上記を踏まえて再度
[exe ファイル ]
cpp からコンパイルして作成された obj ファイルや
lib ファイル内のオブジェクトから main からの一連の流れで
使用する関数を集めて exe ファイルを作成します
libファイルにある実行されない関数等は含めません

lib ファイルの中身のオブジェクトが exe の中に存在するので
静的リンクした事になります。


[dll ファイル ]
obj を集めて作成します。
main関数が無い為、実行する事はできません。
当然全ての関数が dll ファイルに含まれます
内容は lib と同じですが動的リンクであるという点が違います。

[dll の lib ファイル ]
dll から 作成する事が出来ます。
その libファイル内には、dll内の同名の関数の情報があり
中身は dllへアクセスする処理があるだけです


上記を踏まえて再度
[exe ファイル ]
cpp からコンパイルして作成された obj ファイルや
lib ファイル内のオブジェクトから main からの一連の流れで
使用する関数を集めて exe ファイルを作成します

exe の中には dll は含まれておりません
その為 exe のファイルサイズは小さく、dll が無ければ動きません

 (1)-(1)libファイルで静的リンクさせるケース
 (1)-(2)objファイルで静的リンクさせるケース

この2つは大体同じ意味です

[exe ファイル ]
obj を集めて作成します。
main関数が含まれているため、実行すると動作します。
exe ファイルを作成する際、実行されない関数等は含めません

[lib ファイル ]
obj を集めて作成します。
main関数が無い為、実行する事はできません。
当然全ての関数が lib ファイルに含まれます


上記を踏まえて再度
[exe ファイル ]
cpp からコンパイルして作成された obj ファイ...続きを読む

QC++、コンストラクタの引数の数を可変にしたい

次のようなプログラムを作ろうとしています。
あるクラスComponentは
DIM(整数)次元(要素数)のdouble型配列と
ここで DIM は別のところでconstで宣言されています。
(他にもいくつか変数を持っているのですが話に関係ないので割愛します)
とりあえずこんな感じにしたいです。

class Component{
public:
double x[DIM];

Component(double x,double y,double z, ,,,,,); //コンストラクタ
}

ここでコンストラクタComponentは引数にDIM個の実数をとり、たとえば
DIM = 3のとき

Component obj(1.0,2.0,3.0);

と宣言したら
obj.x[0]=1.0
obj.x[1]=2.0
obj.x[2]=3.0
となるようにしたいのです。
むろん代入すること自体は代入すればよいのですが
外で宣言されているDIMによってコンストラクタの引数の数が変わってしまいます。
こういう時はどのような解決策があるでしょうか。
今書いたのと全然違うやり方でもかまいません。
(ただ何個も何個もコンストラクタをオーバーロードするのは避けたいです。
いろんなDIM次元で実験がしたく、きりがありません)。

よろしくお願いいたします!

次のようなプログラムを作ろうとしています。
あるクラスComponentは
DIM(整数)次元(要素数)のdouble型配列と
ここで DIM は別のところでconstで宣言されています。
(他にもいくつか変数を持っているのですが話に関係ないので割愛します)
とりあえずこんな感じにしたいです。

class Component{
public:
double x[DIM];

Component(double x,double y,double z, ,,,,,); //コンストラクタ
}

ここでコンストラクタComponentは引数にDIM個の実数をとり、たとえば
DIM = 3のとき

Compon...続きを読む

Aベストアンサー

型のチェックがゆるくなりますが、可変長引数使って:

template <std::size_t DIM>
class Component {
public:
  Component(double arg0, ...)
  ...

Qスレッド・アウェア(thread-aware)とはどういう意味でしょうか?

スレッド・アウェア(thread-aware)の意味を教えてください。

Aベストアンサー

>スレッド・セーフとは異なる「スレッド対応」なのでしょうか
英語の表現の問題だと思います。

thread-safe (thread-safety)だと、マルチスレッドでも安全に使うことができることを
強調しているのに対して、thread-aware だとマルチスレッドを考慮して作ってますよ。
な感じでしょうか。
英語版のWikipediaでは thead-safe(thread-safety)のエントリはありますが
thread-aware のエントリはないみたいですね。

Thread safety - Wikipedia, the free encyclopedia
http://en.wikipedia.org/wiki/Thread-safety

Threads
http://library.gnome.org/devel/gdk/unstable/gdk-Threads.html#id2755107

のページにある記述を読む限りでは、thread-safe の方が thread-awareよりも
自由に(マルチスレッドであることを気にせずに)プログラムが
組めるということのようです。

GTK+ is "thread aware" but not thread safe ― it provides a global
lock controlled by gdk_threads_enter()/gdk_threads_leave() which
protects all use of GTK+. That is, only one thread can use GTK+ at
any given time.

>スレッド・セーフとは異なる「スレッド対応」なのでしょうか
英語の表現の問題だと思います。

thread-safe (thread-safety)だと、マルチスレッドでも安全に使うことができることを
強調しているのに対して、thread-aware だとマルチスレッドを考慮して作ってますよ。
な感じでしょうか。
英語版のWikipediaでは thead-safe(thread-safety)のエントリはありますが
thread-aware のエントリはないみたいですね。

Thread safety - Wikipedia, the free encyclopedia
http://en.wikipedia.org/wiki/Threa...続きを読む

Q[C++]継承したクラスのコンストラクタの書き方

別の方の質問を拝見して不明点があったので質問します。

class House{
protected:
 int budget;
public:
 House(int x):budget(x){}   (※A)

 省略
}


class Basho:public House{
private:
 int yy;
public:
 Basho(int x,int y):House(x){
  yy = y;           (※B)
 }
 省略


Houseクラスのコンストラクタでメンバ変数への引数の値の代入を※Aの様にブロックの前に記述する方法があることを知りました。(上記プログラム中の※A)
BashoクラスはHouseクラスを継承したもので、コンストラクタで引数yをメンバ変数yyに代入しています(※B)が、これを※Aの様にブロックの前に記述するにはどの様に書けば良いのでしょうか?

 Basho(int x,int y):House(x):yy(y){
 Basho(int x,int y):yy(y):House(x){

試しに上記の様に書いてみたのですがエラーになってしまいました。

別の方の質問を拝見して不明点があったので質問します。

class House{
protected:
 int budget;
public:
 House(int x):budget(x){}   (※A)

 省略
}


class Basho:public House{
private:
 int yy;
public:
 Basho(int x,int y):House(x){
  yy = y;           (※B)
 }
 省略


Houseクラスのコンストラクタでメンバ変数への引数の値の代入を※Aの様にブロックの前に記述する方法があることを知りました。(上記プログラム中の※A)
BashoクラスはHouseクラス...続きを読む

Aベストアンサー

カンマで区切ります。

Basho(int x,int y):House(x), yy(y){

Q【VC++6.0(MFC)】メモリの静的、動的割り当ての意味

いつも大変お世話になっています。
VC++初心者です。

大変初歩的な事なのですが、
理解できていないので質問をさせて頂きたいと思います。

new、deleteはメモリを動的に割り当て、開放しるようですが、
この動的とはどういう意味なのでしょうか。
動的があるのなら、静的にメモリ割り当てというものも
あるのでしょうか。
(静的、動的を区別することによって得られる
恩恵とは何なのでしょうか。)
具体的に例を挙げていただけると幸いです。

Aベストアンサー

>> 「確保される場所が違う」、これをもう少し厳密に言うと
>> 「確保されるメモリの場所が違う」という事でしょうか。
>> (例えば、
>> int i;みたいな変数は、Aという範囲のメモリを使いなさい、
>> new を使った変数は、Bという範囲のメモリを使いなさい、
>> というイメージでしょうか。
>> 稚拙な表現ですみません。)

参照URLにも記載されていますが、【int a】で確保した場合、
関数内のauto変数ならスタック領域、static変数やグローバル変数ならば
静的領域に確保されます。

【new】や【malloc】などで確保した場合はヒープ領域に確保されます。


>> >(可変長のCSVファイルを読み込みや、双方向リストなどのデータ構造を作成したい場合)
>> >いきなりデカイローカル変数等などを用意して使いまわしても良いと思いますが、実用的ではありません。
>> この内容を拝見して「何故、実用的でないのか」と疑問に思いました。
>> (確かに、あまり良くないな、感覚的には思うのですが、
>>  論理的には説明できないのです。)
>> つまり、私の挙げた例を使うと、メモリ範囲Bがあるのに、
>> メモリ範囲Aの部分を大量に消費してしまうから、
>> 実用的でないということでしょうか。

まず、関数内で宣言されるauto変数は、大概の処理系ではスタック領域に確保されるため、
コンパイルオプション等にもよりますが、それほど大きな領域を確保できませんし、
大きな領域を確保出来る環境を前提に作ってしまうと、移植性に乏しくなってしまいます。

newやmallocでメモリを動的に確保出来る利点は以下の通りと私個人では判断しております。

(1)配列では面倒なデータの削除や追加が可能なデータ構造を実現できる。
 通常の配列では、途中のデータを追加・削除しようとすると、データのコピー等が発生するなど
 処理が重たくなってしまいます。
 そこで、リスト構造などデータの追加・削除が容易な仕組みを実現することが必要となり、
 自己参照構造体やメモリの動的確保で実現を行います。

(2)例えば、メモリ領域が最大100M確保可能な環境があるとします。
 データaとデータbがあり、それぞれ可変長(0~100M)だが、
 データaとデータbは足して100Mを超えることは無いものとします。
 上記の場合、データa・データbのそれぞれの最大メモリ使用量は100Mのため
 足して200Mの領域を最初に確保したいと思いますが、環境が最大100Mまでしか
 確保できないため、出来ません。
 そこで動的メモリ確保となってくる訳です。


特にオブジェクト指向でプログラムを組むとなると、各タイミングで各種オブジェクトの
生成・消滅が発生します。
それを前提にある程度のオブジェクト数を最初に用意しておく事も可能ですが、コンストラクタや
デストラクタを活かすコードを書こうとした場合、new・delete演算子で生成・消滅させた
方が良いと思います。

私はwindows畑ではありませんが、microsoftのMFCなどもウィンドウやボタンを生成する毎に
それに対応するCButtonクラス等を継承したクラスを生成していたはずです。

以上

>> 「確保される場所が違う」、これをもう少し厳密に言うと
>> 「確保されるメモリの場所が違う」という事でしょうか。
>> (例えば、
>> int i;みたいな変数は、Aという範囲のメモリを使いなさい、
>> new を使った変数は、Bという範囲のメモリを使いなさい、
>> というイメージでしょうか。
>> 稚拙な表現ですみません。)

参照URLにも記載されていますが、【int a】で確保した場合、
関数内のauto変数ならスタック領域、static変数やグローバル変数ならば
静的領域に確保されます。

【new】や【mal...続きを読む

QC++のクラスで継承先の仮想関数をコンストラクタで呼ぶ方法について

タイトルのとおり、C++のクラスで自分のクラスを継承した先の仮想関数をコンストラクタで呼ぶ方法についてなんですが、これは呼ぶことができないのが常識ですよね。
なのですが、いろいろとやってみたところ、制限はあるものの、なんとかそれっぽいのが作れたんです。
しかし、本当にこのコードが間違ったことをしていないという自信がありません……。
そこで皆さんにお訊ねします。
このコードはセーフでしょうか?アウトでしょうか?

//----- ここから -----

#include <iostream>
struct CLS{
virtual void func()=0;
CLS(){}
template<class T> CLS(T*){reinterpret_cast<T*>(this)->T::func();}
};

struct CLS1:public CLS{
virtual void func(){ std::cout << "x";}
CLS1():CLS((CLS1*)0){}
template<class T> CLS1(T* x):CLS((T*)0){}
};

struct CLS2:public CLS1{
virtual void func(){}
CLS2():CLS1((CLS2*)0){std::cout<<"y";}
template<class T> CLS2(T*):CLS1((T*)0){}
};


int main(){
CLS* x = new CLS1;
CLS* y = new CLS2;
delete x;
delete y;
return 0;
}

//----- ここまで -----

C++の言語規約を読んだりとかはしていないので、自分では判断つきかねるのですが、コンパイラを通したところ、
cl g++ dmc bcc32
あたりで試して全て成功しています。(どのコンパイラでも、ということになるのかはわかりませんが。)
セーフかアウトか…、またその理由をお聞かせください。
暇なときでかまわないので、ご意見いただけたらと思います。

タイトルのとおり、C++のクラスで自分のクラスを継承した先の仮想関数をコンストラクタで呼ぶ方法についてなんですが、これは呼ぶことができないのが常識ですよね。
なのですが、いろいろとやってみたところ、制限はあるものの、なんとかそれっぽいのが作れたんです。
しかし、本当にこのコードが間違ったことをしていないという自信がありません……。
そこで皆さんにお訊ねします。
このコードはセーフでしょうか?アウトでしょうか?

//----- ここから -----

#include <iostream>
struct CLS{
virtua...続きを読む

Aベストアンサー

私も他の方と同様、「アウト」だと思います。

ISO/IEC14882だと12.7あたりで初期化完了してない云々に触れてます。
このコードはundefined behavior(未定義動作)なのでコンパイラにはエラーを検出する責務がありません。
# 当然、どのコンパイラでもそうなる保証なんてないですし、
# エラーを見つけてくれるとも限りません。(だからとりあえずそれっぽく動いて見えている)

実際、上記のコードをちょっと直して、問題をおこすのも簡単です。

 各クラスにメンバ変数を追加して、出力してみてください。

未定義動作として不正参照してるだけで初期化が完了してませんので、
単純に文字を出力してるだけだと気づかないかもしれませんが、
例えば手元のVC7.1で以下のコードを実行するとx,yともn1、n2がゴミになります。
これがご期待の動作でしょうか。(意図してメンバを参照しないコードを書いていますか?)
提示のサンプルはまだしも、未定義動作で言語仕様から逸脱した挙句に、
実際にはメンバすら触れないメソッドの呼び出しは何かうれしいですか?と私は思います。

また、reinterpret_castはポインタを補正をしてくれませんので、
仮想継承とかしてる場合はもっと致命的におかしなことになる可能性があります。
(これも意図して避けていますか?考慮されていないだけですか?)

まぁ、それでもundefined behaviorなので一見正しく動く環境はあるのかもしれませんが、
私ならやはり「アウト」だといいます。

#include <iostream>
struct CLS{
int n1;
virtual void func()=0;
CLS():n1(1){}
template<class T> CLS(T*){reinterpret_cast<T*>(this)->T::func();}
};

struct CLS1:public CLS{
int n2;
virtual void func(){ std::cout << "x" << n1 << ":" << n2<< std::endl;}
CLS1():CLS((CLS1*)0), n2(2){}
template<class T> CLS1(T* x):CLS((T*)0){}
};

struct CLS2:public CLS1{
int n3;
virtual void func(){}
CLS2():CLS1((CLS2*)0), n3(3){std::cout<< "y" << n1 << ":" << n2 << ":" << n3 << std::endl;}
template<class T> CLS2(T*):CLS1((T*)0){}
};


int main(){
CLS* x = new CLS1;
CLS* y = new CLS2;
delete x;
delete y;
return 0;
}

ちなみに、初期化順はもともとが記述順とは別に決まっているものなので、
仮にn3(3)等を前に書くとかしても無駄です。
# undefined behaviorなので「VC7.1で試しても変わりませんでした」が正しいか。

私も他の方と同様、「アウト」だと思います。

ISO/IEC14882だと12.7あたりで初期化完了してない云々に触れてます。
このコードはundefined behavior(未定義動作)なのでコンパイラにはエラーを検出する責務がありません。
# 当然、どのコンパイラでもそうなる保証なんてないですし、
# エラーを見つけてくれるとも限りません。(だからとりあえずそれっぽく動いて見えている)

実際、上記のコードをちょっと直して、問題をおこすのも簡単です。

 各クラスにメンバ変数を追加して、出力してみてください...続きを読む

QスレッドAで信号を送り、返答があったときにスレッドBを起動、スレッドAの信号のデータを初期化する方法

VC6.0で開発しています。
今、次のような処理をどうすればよいか悩んでいます。ヒントになる回答を頂けたら幸いです。

データをやり取りする際、どのような処理を行うか命令するもの(以下、命令A)と、命令された通りのデータを送るもの(以下、送信B)、そして、AとBの通信部分を担うもの(以下、通信C)があります。

データのやりとりは、マルチスレッドで行っています。
データをやりとりするために、スレッドが通信C上で2つ起動しています。1つ目のスレッド(以下、スレッドA)は、送信Bが命令Aから送られる特定のデータ(以下、データA)を受け取れるかをどうかの信号を、命令Aに送るためのものです。2つ目のスレッド(以下、スレッドB)は、データAを通信Cが受け取り、送信Bに渡すときに起動するスレッドです。

スレッドAで、送信Bから命令Aへ、受信の準備ができたことを伝える信号が送られます。その後、命令AよりデータAが送られ、通信CでスレッドBが起動するのですが、データAを通信Cで受信したとき、スレッドAで送っている信号を初期化しなければいけません。

データAを受信したときにはスレッドBが起動しますので、スレッドAとスレッドBの間での処理ということになります。

スレッド処理について、まだまだ不勉強なのですが、よいアイディアがあれば教えてください。
よろしくお願いします。

VC6.0で開発しています。
今、次のような処理をどうすればよいか悩んでいます。ヒントになる回答を頂けたら幸いです。

データをやり取りする際、どのような処理を行うか命令するもの(以下、命令A)と、命令された通りのデータを送るもの(以下、送信B)、そして、AとBの通信部分を担うもの(以下、通信C)があります。

データのやりとりは、マルチスレッドで行っています。
データをやりとりするために、スレッドが通信C上で2つ起動しています。1つ目のスレッド(以下、スレッドA)は、送信Bが...続きを読む

Aベストアンサー

アプリ毎に整理してみました。分からないところは想像で書いています。

--命令A--
(1)「命令A→通信C」のファイルを作成。「送信Bが送信Aに対して、データの要求をしているのかを判別するデータを送信しろ」を送る。
(2)「通信C→送信B、命令A」のファイルを監視。「命令Aにデータ要求」が書き込まれるの待つ。
(3)「命令A→通信C」のファイル2を作成。「送信Bの要求データ」を作成する。
(4)「通信C→送信B、命令A」のファイルを監視。「送信Bはデータの要求をしていない」に書き換わるの待つ。
(5)(1)に戻る。

--送信B--
(1)「通信C→送信B、命令A」のファイルを監視。「送信Bが命令Aに対して、データの要求があるか」が書き込まれるのを待つ。
(2)「送信B→通信C」のファイルを作成して、「送信Bが命令Aに対して、データの要求がある」を書き込む。
(3)「通信C→送信B」のファイルが作成されるのを待つ。
(4)ファイルを読んで、データを何らかの手段で送信。
(5)(1)に戻る。

--通信C--
(1)「命令A→通信C」のファイルが作成されるを待つ。
(2)スレッド1を起動する。
(3)「送信B→通信C」のファイルが作成されるのを待つ。
(4)スレッド1に(3)に進むよう指令を出す。
(5)「送信B→通信C」のファイルを削除する。
(6)「命令A→通信C」のファイル2が作成されたことを検出。
(7)スレッド2を起動する。
(8)このあと???

・スレッド1
(1)「通信C→送信B、命令A」のファイルを作成。「送信Bが命令Aに対して、データの要求があるか」を書き込む。
(2)何らかの指令があるまで(1)を繰り返す。
(3)「通信C→送信B、命令A」のファイルを書き換え。「命令Aにデータ要求」に書き換える。
(4)何らかの指令があるまで(3)を繰り返す。
(5)「通信C→送信B、命令A」のファイルを書き換え。「送信Bはデータの要求をしていない」に書き換える。
(6)「命令A→通信C」のファイルを削除する。
(7)スレッドを終了する。

・スレッド2
(1)スレッド1に対して、指令を送り(5)に移行するように促す。
(2)「命令A→通信C」のファイル2を読み込み、「通信C→送信B」のファイルを作成する。コピー後「命令A→通信C」のファイル2は削除する。
(3)スレッドを終了する。

勘違いがあったら訂正をお願いします。

全体として問題を感じたので何点か上げます。
・ファイル作成を条件に動いている所があるが、ファイル内容が全部書き出されていないうちに動き出してしまわないか?
・必要な動作に対してやっていることが複雑である。処理の起点はなぜ送信Bの要求から始まらないのか?命令Aから始まる理由は?
・ファイルの後始末が不明確。
・スレッド1の処理で、何度もファイルを書き換える理由は?
・命令Aと送信Bが通信していれば作れそうな気がする処理で、通信Cが必要な理由が分からない。


シンプルにするとしたら、こんな感じには出来ないのでしょうか?
一応命令Aを起点にしています。スレッドがなくなってしまうので、このアプリの構成がスレッドの勉強のためだったら申し訳ない!

--命令A--
(1)送信Bにメッセージで要求がないか問い合わせる。
(2)送信Bの返事を待つ。
(3)送信要求なら、ファイルを作成する。送信不要なら(1)に戻る。
(4)送信Bにメッセージでファイルが出来たことを知らせる。
(5)送信Bの返事を待つ。
(6)(1)に戻る。

--送信B--
(1)命令Aから要求の問い合わせを待つ。
(2)命令Aにメッセージで要求の有無を送信。
(3)要求無しなら(1)に戻る。
(4)命令Aからファイルの完成メッセージが届くのを待つ。
(5)ファイルを読んで何らかの方法で送信する。
(6)ファイルを削除する。
(7)命令Aにメッセージで送信が完了したことを知らせる。
(8)(1)に戻る。

相互の通信にはWindowsAPIのPostMessageを使用する予定です。
ただし、両方のアプリにhWndが必要なので両方ともウィンドアプリである必要があります。
http://yokohama.cool.ne.jp/chokuto/urawaza/api/PostMessage.html

アプリ毎に整理してみました。分からないところは想像で書いています。

--命令A--
(1)「命令A→通信C」のファイルを作成。「送信Bが送信Aに対して、データの要求をしているのかを判別するデータを送信しろ」を送る。
(2)「通信C→送信B、命令A」のファイルを監視。「命令Aにデータ要求」が書き込まれるの待つ。
(3)「命令A→通信C」のファイル2を作成。「送信Bの要求データ」を作成する。
(4)「通信C→送信B、命令A」のファイルを監視。「送信Bはデータの要求をしていない」に書き換わるの待...続きを読む


人気Q&Aランキング