ページ 11

オブジェクトの宣言

Posted: 2013年7月03日(水) 18:43
by アタゴ
いまゲーム作りで初期化で困っているのです。それは宣言の時に自作関数の中で宣言(初期化)したオブジェクトをグローバル変数みたいな扱いができるオブジェクト(ローカルとして宣言しておいて宣言時の関数から抜けても残る)として作ることができるのでしょうか?またこういう場合はグローバル変数と同じように宣言しないといけないのでしょうか?コードが必要なら載せます。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 18:48
by softya(ソフト屋)
言語も書かれていないので答え辛いです。
C言語ならstaticにすれば寿命はプログラム存在中です。
なんか、オブジェクトの寿命とスコープを混同されているような質問なので、そこら辺を明確にしてください。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 19:00
by アタゴ
あ、忘れていました。言語はC++です。staticとはどこで宣言しても宣言後でそのプログラム内ならどこでも使えるという意味でしょうか?

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 19:06
by nil
>staticとはどこで宣言しても宣言後でそのプログラム内ならどこでも使えるという意味でしょうか?
いいえ、定義の場所によります。

細かいところを省略して簡単に言いますと、
関数内であればその関数内のみ、
関数外であればそのファイル内のみ、です。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 19:06
by softya(ソフト屋)
アタゴ さんが書きました:あ、忘れていました。言語はC++です。staticとはどこで宣言しても宣言後でそのプログラム内ならどこでも使えるという意味でしょうか?
それはスコープが問題になります。
C++ならばクラス内(大雑把)、グローバル、ファイル内、ローカルなどのスコープに別れますね。
あと、インスタンス生成のタイミングの問題も有るので、そんな簡単には片付かないです。

そもそも、C++でグローバルスコープなのは余り良い設計とは言えないと思います。
オブジェクトの更新は制限されたクラスなのでしょうか?

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 19:11
by アタゴ
制限されたクラスとはどう言う意味ですか?
それともし
static class-name A;
とH()内で作ったとするとmain()内でAは使えるのですか?
そもそもグローバルスコープとはどう言う意味ですか?
質問が多く、勉強不足ですみません

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 20:24
by softya(ソフト屋)
制限されたクラスとはどう言う意味ですか?
内部の情報をできるだけカプセル化して、基本的に書き換えられないように更新メソッドを持たないクラスですか?って質問です。
グローバルで問題になるのは、不用意な更新ですので。
それともし
static class-name A;
とH()内で作ったとするとmain()内でAは使えるのですか?
そもそもグローバルスコープとはどう言う意味ですか?
質問が多く、勉強不足ですみません
スコープは、ここを読んでいただきましょうか。
「スコープ - Wikipedia」
http://ja.wikipedia.org/wiki/%E3%82%B9% ... C%E3%83%97

と言うことで関数内のインスタンスは関数内にしか見えません。それはstaticしても同じです。
あと無闇に関数外に持ち出すのは設計セオリーがしっかいしていないとバグになります。

それと関数内で作ったインスタンスは、関数を抜けるときにデストラクトされます。つまり寿命が関数を抜けるまでとなります。
staticにすれば、寿命はプログラム生存内となりますが、グローバルに参照が出来ることが目的ならローカルなインスタンスにする意味が無いです。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 20:53
by ym114
static変数の初期化が行われると,二回目以降はその行は無視されます.変数はずっと生きているからです.
この性質がグローバル変数と似ているのでスコープ限定のグローバル変数のように説明されることもあります
しかし,スコープ内で生きているからといってスコープ外から見えるわけではありません.
スコープ内で宣言された変数はどう頑張ってもスコープ外からは見ることができないのです.
ということでstatic変数は忘れてください.

自作関数で初期化して,それを外に持ち出したいときは
1.自作関数(スコープ)の外で宣言された変数に値を代入して初期化する
2.自作関数の中で宣言された変数をreturn で返して(値はコピーされます),関数呼び出し側がそれを受け取る
3.自作関数が仮引数に変数へのポインタ/参照を受け取り,それを初期化する
のいずれかの方法を取るのが一般的だと思います.

1.はグローバル変数を初期化するケースです.簡単ですが誰がいつその変数の値を変えたか全く分からなくなるので良い設計ではありません.
2.と3.するように自作関数を作るべきです.

基本的に関数は機械の部品(モジュール)のようなもので,部品単体で何らかの仕事をするものです.
部品は外部の変数に勝手にアクセスせず,部品の中で仕事を終わらせるべきだとおもいませんか?

(おまけ)
// 2.の初期化方法
Object a = CreateObject();
// 3.の初期化方法
CreateObject(&a);
CreateObject(a);
// 生成方法に幅を持たせたい場合は引数アリの関数を作る
Object a = CreateObject(100,200);

(おまけ2)
static変数のポインタを返すような関数ならば,文字通り"自作関数の中で宣言された変数をグローバル変数のように扱う"ことができます.
これはC++でシングルトン, つまりグローバル変数もどきを作るときに使われるテクニックです.

コード:

int* Function()
{
    static int x = 0;
    return &x; // この値はずっと変わらないのでFunction()の返り値はずっと同じ = グローバル変数のように扱える
}

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 21:11
by KORYUOH
ym114 さんが書きました: (おまけ2)
static変数のポインタを返すような関数ならば,文字通り"自作関数の中で宣言された変数をグローバル変数のように扱う"ことができます.
これはC++でシングルトン, つまりグローバル変数もどきを作るときに使われるテクニックです.

コード:

int* Function()
{
    static int x = 0;
    return &x; // この値はずっと変わらないのでFunction()の返り値はずっと同じ = グローバル変数のように扱える
}
Singletonですがこういう書き方も出来ます。

コード:

int& Function(){
	static int x=0;
	return x;
}
後はC++が新しいものであるならばstd::shared_ptrが使えます。

使い方はこんな感じ

コード:

//C++11でコンパイルして動作確認済み
#include <iostream>
#include <memory>            // std::shared_ptr
#include <string>
//クラス
class A{
public:
 A():mName(""){}
 A(const std::string& name):mName(name){}
 void say(){
     std::cout<<"HELLO,"<<mName<<std::endl;
 }
 private:
 std::string mName;
};
//作る関数
std::shared_ptr<A> Create(const std::string& name){
    return std::make_shared<A>(name);
//もしくは
// return std::shared_ptr<A>(new A(name));
}

int main(void){
    
    std::shared_ptr<A> inst = Create("KORYUOH");
    
    inst->say();
    
    return 0;
}



実行結果

コード:

HELLO,KORYUOH

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 21:27
by softya(ソフト屋)
そもそも、グローバルスコープにする必要性があるのか?って事が一番問題だと思います。
どうしても必要なら、一番安全な設計を検討して、その上でどのテクニックを使うか検討するのが正しい手順かなと思います。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 22:26
by アタゴ
newやdeleatなんかも似たようなことができると聞いたのですがこの二つはstaticとどう違うのですか?

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 22:34
by softya(ソフト屋)
アタゴ さんが書きました:newやdeleatなんかも似たようなことができると聞いたのですがこの二つはstaticとどう違うのですか?
newやdeleteは自分で生存寿命を決めることができます。
あるいは、KORYUOHさんが書いたstd::shared_ptrは更に寿命をクラス任せにしてオブジェクトとが使われなくなったらdeleteするという高度な仕組みです。
この質問もそうなのですが、スコープとは別の生存寿命に関するものなのでスコープの問題は別に存在します。

と言うことで、スコープ問題と生存寿命問題は同一視して考えないでください。
同時に考えないといけないものですが、同じものではありません。

【追記】
「変数の記憶寿命とスコープ」
http://www2.ee.knct.ac.jp/el/E3/E305/lifeandscope.html
まず、これをよく頭に叩きこんでみてください。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 22:51
by h2so5
http://www2.ee.knct.ac.jp/el/E3/E305/lifeandscope.html
静的記憶寿命を持つ変数の記憶領域がヒープ領域に作られると書いてありますけど、これ嘘じゃないですか?
処理系によってはヒープ領域なのかもしれないですけど。

Re: オブジェクトの宣言

Posted: 2013年7月03日(水) 22:54
by softya(ソフト屋)
h2so5 さんが書きました:http://www2.ee.knct.ac.jp/el/E3/E305/lifeandscope.html
静的記憶寿命を持つ変数の記憶領域がヒープ領域に作られると書いてありますけど、これ嘘じゃないですか?
処理系によってはヒープ領域なのかもしれないですけど。
あうっ。失礼しました。そんな余分なこと書いてありましたか。よく精査せずすいません。
何処か分かりやすそうな所ご存知ありませんか?

Re: オブジェクトの宣言

Posted: 2013年7月04日(木) 01:25
by KORYUOH
とりあえず基本をまとめるとこんな感じですかね

コード:

int global=0; //プログラムのどこからでも書き換え参照可能、プログラムが終了するまで生きている

static int static_global=0;//プログラムが終わるまで生きているけれどこのファイルの中からしかアクセスできない、逆にこのファイル内からならどこからでもアクセスできる。

void func(){
	int local=0;//この関数内だけ生きていて抜けるときには消える。外からはアクセスできない
	static int val=0;//この関数内からしかアクセスできないが関数を抜けても生きている。プログラムと終了で消える。

	int* pointer = new int(0);//deleteされるまで生きている。deleteされないとバグの原因になる。
	delete pointer; //newされたファイルを消す。newしたら必ず消さないといけない。
	
}

Re: オブジェクトの宣言

Posted: 2013年7月04日(木) 12:38
by softya(ソフト屋)
とりあえず、良い参考サイトもなかったので、「変数の記憶寿命とスコープ」の記憶領域の記述は特定の環境に限定されると補足しておきます。
これが適用されない環境もあるので記憶領域の記述に関しては覚えないでください。[修正]

Re: オブジェクトの宣言

Posted: 2013年7月06日(土) 10:45
by アタゴ
詳しく教えていただきありがとうございます。
自分でこのことを参考にいろいろやってい行きたいと思います。