参照について(C++)

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
tk-xleader

参照について(C++)

#1

投稿記事 by tk-xleader » 18年前

C++についてのサイトで、関数で呼び出し元の変数を書き換える時は
参照ではなくポインタを使うのが暗黙のルールだと書いてあったのですが
なぜでしょうか?どちらかといえば参照を使うほうがより安全なプログラムが
書けると思ったのですが。どうでしょうか?

Justy

Re:参照について(C++)

#2

投稿記事 by Justy » 18年前

参照ではなくポインタを使うのが暗黙のルール
 そういうローカルルールが存在するのはたしかです。
 1つには呼び出し元にしても呼び出し先にしても見ただけで、各変数の inと outが明確になるようにする
意図があると思われます。

 例えば
[color=#d0d0ff" face="monospace]void SomeFunction(SOME_BIG_DATA &nonmodifiableData, SOME_BIG_DATA *modifiableData);[/color]
 の場合、呼び出し先ではポインタ渡しされた modifiableDataは中身を変更し、
参照渡しされた nonmodifiableDataは変更しないことを obj->memberか obj.memberで行うかで(視覚的に)
見分けることができることを狙っています。

 呼び出し元でも
[color=#d0d0ff" face="monospace]SomeFunction(bigData1, &bigData1);[/color]
 となり、引数の型がポインタかどうかで変更されるかどうかがわかるようになります。


 C++的には
[color=#d0d0ff" face="monospace]void SomeFunction(const SOME_BIG_DATA &nonmodifiableData, SOME_BIG_DATA &modifiableData);[/color]
 のように constをつけることで intと outの区別をつける方法の方がいいかな、とは思います。
 できるだけ constが付けられるなら constを付けるのが望ましいですから。

 ただ、自分のソースだけを相手にしている場合ならそれでもいいのですが、
他人のライブラリやソースを使っている場合、const付きのクラスオブジェクトの扱いに困ることがあります。

 例えば本来であれば
[color=#d0d0ff" face="monospace]class A
{
public:
    int getA() const        { return m_a; }
  
private:
    int     a;
};[/color]
 こうなっていなければならないところを
[color=#d0d0ff" face="monospace]class A
{
public:
    int getA()        { return m_a; }
  
private:
    int     a;
};[/color]
 のようにメンバ関数 getA()に constが付いていない場合、
[color=#d0d0ff" face="monospace]void CopyA(const A &a, int &b)
{
    b = a.getA();
}
[/color]
 
 とすると const付きの Aのオブジェクト aからは getA()は呼び出せないのでコンパイルエラーになります。

 ソースが自分の管理下にあれば修正すれば済みますが、そうでない場合仕方なく constを付けないで
[color=#d0d0ff" face="monospace]void CopyA(A &a, int &b);[/color]
 と定義することになり、結果(引数の名前以外では)intと outの区別が付かなくなります。

 というわけで、ポインタを使って区別すればいいんじゃない? というのが2つ目の理由になります。


 あともう1つあってC言語しか知らない人が見た場合、参照渡しが値渡ししているように
見えることです。
 本当に値渡しであれば、呼び出し元の方の値は変更されないので、勘違いしても
(細かい動作はともかく、呼び出し元の値が変更されないという)結果が同じである確率は高くなります。


 たしか理由としてはこんな感じだったかと思います。
 他にも細かく探せば理由はありそうですね。


 ちなみに私個人としてはポインタか参照かはどっちでもいいです。
 いつもは、そのルーチンにおいてポインタか参照のどちらが都合がいいかで決め(大抵参照になります)、
必要なところにちゃんと constつけ、引数など名前で outがわかるようにしています。

tk-xleader

Re:参照について(C++)

#3

投稿記事 by tk-xleader » 18年前

質問した僕が言うのも何ですが。個人的な開発しかやっていませんし、(というかそもそも中3生)
C++にできるだけ移行しようとしているので参照のほうがいいと思ったのです。独習C++にも参照の
ほうが優れていると書いてあったので、どっちかなと思ったので投稿しました。個人開発ではどっ
ちでもあまり問題はありませんよね?

Justy

Re:参照について(C++)

#4

投稿記事 by Justy » 18年前

>個人開発ではどっちでもあまり問題はありませんよね?
 ということであれば、全然問題ないです。
 用途とお好みに合わせて、使い分けて下さい。

tk-xleader

Re:参照について(C++)

#5

投稿記事 by tk-xleader » 18年前

しかし、C++というのはいろいろと便利な機能がついていて
プログラミングがやりやすいですね。個人的にはクラス・
テンプレート、STLがいい機能だと思いますが、どうでしょ
うか。

Justy

Re:参照について(C++)

#6

投稿記事 by Justy » 18年前

C++というのはいろいろと便利な機能がついていて プログラミングがやりやすいですね
 たしかに。
 
 ただ、高機能すぎるというか、覚えることがあまりにも多すぎて、
付いていけない人が続出する、という面もあります。
 周りに C++使いは多くいるのですが、個々のレベルの差が激しいんですよ、これが。

 体感的にですが今の C++の世界って、Cの 10倍以上はあるんじゃないでしょうか。
 全部覚える・使う必要はないにしても、これだけ世界が広いとなかなか
それらを押さえるのは大変です(^^


個人的にはクラス・ テンプレート、STLがいい機能だと思いますが
 やはり(STL含む)テンプレートでしょう。
 先の 10倍説のうち 7倍くらいはテンプレートですから。

組木紙織

Re:参照について(C++)

#7

投稿記事 by 組木紙織 » 18年前

>参照ではなくポインタを使うのが暗黙のルール

ポインタを使うときには、
ポインタが指す内容でなく、ポインタ自体が書き換えられる可能性があるので、
constをつけてそれを防いだほうが良いとおもいます。

>体感的にですが今の C++の世界って、Cの 10倍以上はあるんじゃないでしょうか。

それは私もそう思います。c++のコンパイラを個人で作れる人は、世の中に数えるほどしか
いないらしいですし。

てきとーに使うだけなら言語使用だけ覚えておけばよいのですが、安全に、開発をしやすく
使おうと思うといろいろな副読本を読んでおかないと、難しいのもc++の特徴のように思います。
c++を最大限使おうと思ったらデザインパターンやオブジェクト指向設計などの
関連する部分も押さえておかないといけないのがc++使いの悩みどころだと思います。

参照について言うと、独立参照なんて、いつ、どこで、何のために使うのかがまったく分からないので
c++になくても問題はないのではないか。
と思っています。
というより、
独立参照はc++には必要がないものだと思っています。

tk-xleader

Re:参照について(C++)

#8

投稿記事 by tk-xleader » 18年前

なるほど、確かにC++はCから拡張しすぎて肥大化した部分も多いといわれています。
しかし、僕は個人開発ですし、まだCをやってから4ヶ月でC++に移行したのですが、
とりあえず、Cの全貌を知っているわけではありませんが、コンソールアプリなら一
応作れるので、たぶんC++も全ての仕様を把握しなくても、大丈夫だと思いますが。
僕も継承とか仮想関数や実行時型情報、C++の入出力もよく分からないです。だから
ぼくがC++を使うと、cout、cinを使う入出力ぐらいしか、使わなくて、後はC形式の
入出力を使ったりして、C++を生かしきれてるのかな…って思ったりします。

バグ

Re:参照について(C++)

#9

投稿記事 by バグ » 18年前

C++の全てを学習する事が目的なのですか?
それとも、何か組んでみたいアプリケーションがあっての学習なのでしょうか?
前者ならば、それはそれで素晴らしい事だと思いますが途方も無い学習量になりそうですね(;^_^A
もし後者ならば、目的を達成する為に必要な知識を絞り込んで学習するほうがスマートだと思います。
その理由は、プログラム言語なんて、所詮は手段であって目的ではないからです。
これは、勉強しようという姿勢を否定しているコメントではないので、そこはご理解下さいm(__)m

tk-xleader

Re:参照について(C++)

#10

投稿記事 by tk-xleader » 18年前

ただ、Cでは最近C++の仕様を取り込むような拡張をC99でやりましたよね。
しかし、それでもC++ほどの大きさになったわけではないわけですよね。僕
はC++のいいところとして、wchar_t型がキーワードになった事があると思う
のです。理由は、初期のCではwchar_tがなかったために、あとからtypedef
として定義しましたよね。それで思ったのですが。たぶんCのwchar_tという
のは、普通の整数型と同じとして扱われるのではないでしょうか(コンパイラにとって)。つまり、
整数型と文字型の混同ができてしまうのではないかという事です。それこそ
デバッグの量を増やす事になりかねないのではないかと思うのです。C++では
型の制限が厳しくなっています。それは型の混同によるバグを減らすためだと
思います。ただ、malloc()の戻り値をキャストしなければならないというのは
少々面倒くさい気もしますが。

Justy

Re:参照について(C++)

#11

投稿記事 by Justy » 18年前

# 組木紙織さん
c++のコンパイラを個人で作れる人は、世の中に数えるほどしかいない
 そうでしょうねぇ。
 作れといわれても、ある程度形になるまで一体何人の人員と期間がかかることやら。


てきとーに使うだけなら言語使用だけ覚えておけばよいのですが
安全に、開発をしやすく 使おうと思うといろいろな副読本を読んでおかないと
 そうですね。
 オブジェクト指向1つとっても最初のうちは頭でわかったつもりでも、すぐにはコードに書けなかったりします。
 C++の危険な使い方を回避するための方法も複雑で多岐にわたっていて結構大変です。
 必要に応じて順次覚えていくのがベストですね。

 とはいえ、仕事じゃなければそんなん無視して突っ走るのもありかな、とはおもいますが(w


独立参照はc++には必要がないものだと思っています
 独立参照という言葉にあまり聞き覚えがないのですが、関数の引数や戻り値ではなく
単独で用いられる(宣言時に明示的な初期化が必要な)参照ということでいいでしょうか?

 であれば私は必要ですね(そうでなければここは無視して下さい)。
 ないと無駄なコピーをすることになったり、無駄な処理を強いられることになったりしますので。


# tkmakwins15さん
たぶんCのwchar_tという のは、普通の整数型と同じとして扱われるのではないでしょうか
 typedefの元になった型と同義と見なされるので、そうなりますね。
 wchar_tが予約語になっていれば、インクルードなしに使えますし、型としては別に扱われるので関数の
オーバーロードなどでは他の整数型とは区別されます(ただ wchar_tから整数型への汎整数昇格もあるので、
少し注意が必要ですが)。


C++では 型の制限が厳しくなっています。
それは型の混同によるバグを減らすためだと思います
 これはその通りです。
 型キャストが4種類に分けられ、Cスタイルのキャストが非推奨になったのもそういう理由が関係していますね。


malloc()の戻り値をキャストしなければならないというのは
 C++で malloc/freeはあまり使われません(というか非推奨)。
 new/deleteを使えばキャストの必要はなくなりますし、sizeof演算子すら不要になりますよ。
 

tk-xleader

Re:参照について(C++)

#12

投稿記事 by tk-xleader » 18年前

malloc()関数が推奨されない理由というのは、そういう型の問題もありますが。
new演算子と比べて、決定的な違いがあるのですよね。malloc()は単なる領域と
してメモリを確保しますが。newは型としてメモリを確保しますよね? この違い
というのは、やはりC++の型に対して厳格になったところからきていると思います。
ただ、消費税などのお金の計算においては、double型からint型にキャストしないと、丸め
誤差が発生して不正確になりますよね、それにfloor()関数などの整数値となっ
た時に、int型に代入したい時もありますよね。そういう場合は、キャストが優
れた手段になる時もありますよね…。また、windows APIの操作においても、ハ
ンドル値などやスタイル指定などの時に、C++だとキャストが必要な時が多いですよね

組木紙織

Re:参照について(C++)

#13

投稿記事 by 組木紙織 » 18年前

>単独で用いられる(宣言時に明示的な初期化が必要な)参照ということでいいでしょうか?
そのとおりだとおもいます。
そのサンプルが。
int main()
{
	int x;
	int &ref =x;
  
  	x=10;	//この二つの文の
	ref =10;//機能は同等である。
	
	ref = 100;
	//100を二回出力する
	
	cout << x << ' ' << ref << "\n";

	return 0;
}
となっており、これからどのように使えばよいかが全然見当がつかないので、必要ないと思っています。

GPGA

Re:参照について(C++)

#14

投稿記事 by GPGA » 18年前

構造体の中に構造体があって、またその中に構造体あり
その先の変数に対して複数回の処理をする、などという場合に必要になるのではないでしょうか?
void func(HOGE hoge)
{
	int& x = hoge.zzz.yyy.x;

	// xに対して複数回処理する

	return 0;
}
 
これでしたら、構造体のメンバにアクセスする処理を
省くことが出来るため、この参照方法の意味が出てくると思います。

Justy

Re:参照について(C++)

#15

投稿記事 by Justy » 18年前

# tkmakwins15さん
 malloc()が推奨されないのはクラスオブジェクトのコンストラクタが呼ばれないからです。
 free()も同様にデストラクタが呼ばれないからです。
 自分で明示的に呼ぶなら話は別ですけど。


ただ、消費税などのお金の計算においては~(略)
 まぁ、お金の計算を doubleを使って行うことの是非はともかくとして、
もちろん C++といえどキャストは必要なときには必要になります。

 C++のキャストにおいて、Cと異なるのは RTTIを利用した dynamic_castが可能になっていることです。
 この差は大きいですよ。



# 組木紙織さん
これからどのように使えばよいかが全然見当がつかないので、必要ないと思っています。
 これはたしかに要らない(w
 でもこれは例があまりにも・・・。

 こんな例でしたらどうでしょう。
[color=#d0d0ff" face="monospace]#include <iostream>
#include <cstdlib>
#include <ctime>

namespace 
{
    class A
    {
    public:
        int getData()  { return std::rand(); }
    };
    
    class B
    {
    public:
        A &getA()
        {
            //  ここでものすごく時間のかかる処理をしてから m_aを返す
            for(int n=0; n<0x100000; ++n)
                printf("");
            return m_a;
        }
    private:
         A   m_a;
    };
}

int main()
{
    std::srand(std::time(NULL));
    const int loop_times = 30;
    
    B   b;
    {
        //  1)参照を使わないでそのままアクセス
        for(int n=0; n<loop_times; ++n)
            std::cout << "type 1 :" << b.getA().getData() << std::endl;
    }
    {
        //  2)参照を使ってアクセス
        A &refA = b.getA();
        for(int n=0; n<loop_times; ++n)
             std::cout << "type 2 :" << refA.getData() << std::endl;
    }
    return 0;
}[/color]
 1)はかなり時間がかかりますが、2)は比較的速く処理が終わります。
 これは無駄なループを使っているので実際には意味がありませんが、
このように別のクラスが持つ情報へのアクセスを簡易・高速に、或いは可読性向上の為、
参照を使って別の名前をつけておくことは、よくあります。

組木紙織

Re:参照について(C++)

#16

投稿記事 by 組木紙織 » 18年前

GPGAさん、 Justyさんコメントありがとうございます。

独立参照(independent reference)という名前が出ているのは私が持っている書籍の中では
[独習C++]のなかだけなんですよね。
この中では
"繰り返しますが、この種の参照を使用する利点はほとんどありません。"
とかなり強調して、使わないほうがよいと書いてあり、私自身使い方を考えても利点が分からなかったので、
この筆者の意見と同一でした。
[プログラミング言語C++第3版]で参照のところを調べてみると、このタイプの参照に関して
何もコメントをしていないのもありますが。

このタイプの参照を使って読み込む場合の利点は分かりました。
書き込みの場合は、必要があるかどうか分かりませんが、その場合の利点を考えてみようを思います。

tk-xleader

Re:参照について(C++)

#17

投稿記事 by tk-xleader » 18年前

ただ、calloc()関数は使う価値はあると思います。それは、new演算子と違って
動的に確保したメモリ領域を、自動的に初期化してくれますので、calloc()に
ついてはmalloc()やnewと違ういいところがあると思います。

また、参照というのは、Cであればポインタを使って危険な手作業をして書い
ていたプログラムを、自動的に処理してくれる機構なのだと思います。だとす
れば、不正なメモリ領域のアクセスという、危険極まりなく、また見つかりに
くいバグを排除することが、可能になるのではないでしょうか。STLとして、
stringクラスを導入したのも、そのような理由があるのではないでしょうか。
charのポインタ型を使った終端文字式文字列には、どうしても不正なメモリア
クセスの危険がまとわりつきますから。ポインタをC++から出来るだけ排除し
ようという考え方に基づいて参照が導入されたのだと思います。

Justy

Re:参照について(C++)

#18

投稿記事 by Justy » 18年前

私自身使い方を考えても利点が分からなかったので、この筆者の意見と同一でした

 先に組木紙織さんが提示されたサンプルで、無理矢理利点を挙げるとしたら

・ 同一変数を異なる用途で使い回す際の明示化
・ コンパイラへの最適化の妨害
・ 難読化

 くらいしか思いつきません・・・(これは利点なのか!?)。


 と、ぐぐってみたら
ttp://monpe.cliff.jp/computer/cpp/160_cpp_ed_doc.html

 こちらでも同じようにあまり使わない、と書いていますね。
 う~ん、謎ですね。

tk-xleader

Re:参照について(C++)

#19

投稿記事 by tk-xleader » 18年前

よく考えてみたらポインタを使っても同一のプログラムは書けるのですよね…
例えばこの二つは同じ挙動をします。
#include<iostream>
using namespace std;

int main()
{
	int x;
	int *p_x = &x;
	x = 3;
	cout << x;
	*p_x = 10;
	cout << x << "," <<*p_x ;
	return 0;
}
と、以下のプログラム
#include<iostream>
using namespace std;

int main()
{
	int x;
	int &p_x = x;
	x = 3;
	cout << x;
	p_x = 10;
	cout << x << "," << p_x ;
	return 0;
}
まぁどっちのプログラムにも言えることといえばどちらも無駄な事してますよね…。
この形の参照は確かに使わないかな………。かといってC++でもしこのようなプログ
ラムを書くとしたら安全性は下のほうが大きいですね。

Justy

Re:参照について(C++)

#20

投稿記事 by Justy » 18年前

calloc()関数は使う価値はあると思います
 とはいえ C++では使いどころが少ないですね。
 どうしても0初期化したければ後から明示的に std::memsetなりをすればいいですし、
 そもそも malloc/calloc/newが混在していると、どうやって確保したかを
そのポインタからは知る方法がないので、解放方法に混乱が生じるという問題もあります。


C++でもしこのようなプログラムを書くとしたら安全性は下のほうが大きいですね。ね
 Yes。
 p_x = 10とかやってしまう危険は少なくともなくなりますからね。

tk-xleader

Re:参照について(C++)

#21

投稿記事 by tk-xleader » 18年前

出来れば、C++にnewを実装する時に、動的配列の初期化ができるように
するべきですよね。newの動的配列にcallocのような初期化がないのは、
何かしらの技術面の問題があるからだと、本には載っていたのですが、
少なくともスカラ型に対してはそれができるように実装すべきだったと
僕は思います。結構変数の初期化を忘れてバグが発生したという事例は
あるので、自動的にそれができればだいぶその手のバグが減ると思いま
す。

Justy

Re:参照について(C++)

#22

投稿記事 by Justy » 18年前

>newの動的配列にcallocのような初期化がないのは、 何かしらの技術面の問題があるからだと
 技術的な問題というか、遅くなる方を標準にするのは好ましくないからでしょう。
 C++が使える環境全てにおいて高速な CPUやメモリがあるわけではないので。

 それに C++は operator newをオーバーロードすることができるので、それを使えば
いかようにでも出来るので特に問題は無いのではないでしょうか。

YuO

Re:参照について(C++)

#23

投稿記事 by YuO » 18年前

> ただ、calloc()関数は使う価値はあると思います。それは、new演算子と違って
> 動的に確保したメモリ領域を、自動的に初期化してくれますので、calloc()に
> ついてはmalloc()やnewと違ういいところがあると思います。

callocなんて使い道ほとんどないと思うのですが。
整数型のみからなる配列,構造体相手にしか使えない時点であまり意味がない……。
そもそも0に値をセットすることは初期化ではないですし。
# 初期値として本当に必要な値を設定することが初期化。calloc/memsetは決して初期化してはくれない。

そもそもC由来の記憶域制御関数を必要とする場面が全く思い浮かばない……。
ついでに,new[/url]を必要とする場面も。


> 出来れば、C++にnewを実装する時に、動的配列の初期化ができるように
> するべきですよね。

そもそもnew[/url]を使うことが皆無なので不要でしょう。
std::vector使えば初期値を設定できますし。

tk-xleader

Re:参照について(C++)

#24

投稿記事 by tk-xleader » 18年前

うーん、ただnewはクラスオブジェクトを作成する時に必要になるのではないでしょうか
deleteを使えばデストラクタが呼ばれるという事で、明示的になると思いますが、それに
僕はテンプレートはわかるのですがSTLについてはstringクラスしかまだわからず、vector
についてはよく分からないので、newによる動的配列で実装しているのです。vectorクラ
スがわかったらそれ使って動的配列実装しようと思いますが。

YuO

Re:参照について(C++)

#25

投稿記事 by YuO » 18年前

> うーん、ただnewはクラスオブジェクトを作成する時に必要になるのではないでしょうか

new自体は使いますよ。
RAIIに則ってすぐにスマートポインタに格納しますが。

new[/url] (配列用のnew) を使わないだけです。


> deleteを使えばデストラクタが呼ばれるという事で、明示的になると思いますが、

deleteはコード中に出てくることはまずないですね。


> vectorクラスがわかったらそれ使って動的配列実装しようと思いますが。

std::vector「で実装する」んでじゃなく,std::vector「が実装そのもの」です。
わざわざ,
class DynamicArray<T>
{
private:
    std::vector<T> data_;
public:
    DynamicArray<T> (int size, const T & init = T()) : data_(size, init) {}

    T& operator[/url] (int index) { return data_[index]; }
    const T& operator[/url] (int index) const { return data_[index]; }
};
なんてクラス作るんだったら,std::vectorをそのまま使えばいいわけでして。

tk-xleader

Re:参照について(C++)

#26

投稿記事 by tk-xleader » 18年前

しかし、STLというのはあまりにも大きすぎて理解するのに相当の時間がかかると思います
STLがC++に追加された事で、ほぼ完璧にデバッグされたコードやデータ型を使う事ができる
という利点がありますが、その反面、C++の完全な習得が難しくなり、その上にC++の標準化
が遅延してしまったというあまりよくないことまでもたらしてしまったという欠点もあるの
ですよね。これ以上にC++が巨大化すると、個人でC++のコンパイラを作る事が、ほぼ不可能
になる気がします。ただ、C++に追加して欲しい仕様があります。それは64ビット整数のサポ
ートです。そうすれば、あと30年くらいしたら全世界中のC/C++で書かれたプログラムが誤作
動をするという2038年問題に、対応できると思います。(time_tを64ビット化すれば)

YuO

Re:参照について(C++)

#27

投稿記事 by YuO » 18年前

> しかし、STLというのはあまりにも大きすぎて理解するのに相当の時間がかかると思います

大きいから理解するのに時間がかかることはないです。
時間がかかるとしたら,パラダイムシフトのためでしょう。
Generic-Programmingというプログラム手法を使っているため,それに慣れていない開発者が理解に時間がかかっているだけです。


> その反面、C++の完全な習得が難しくなり、

完全な習得とは?

プログラム言語は道具ですから,必要な部分だけ覚えて,後は仕様書でも見ながら使えばよいのです。


> これ以上にC++が巨大化すると、個人でC++のコンパイラを作る事が、ほぼ不可能
> になる気がします。

なぜ個人でC++コンパイラを作成することにこだわるのかがわかりませんが……。
現時点においても,文法の一部 (ぶっちゃけexport) を実装するためにはリンカサポートが必須になっています。
つまり,コンパイラを作成するだけではC++を実装しきれません。

はっきり言って,個人でC++コンパイラを作成できるかどうかは意味のない論です。
最終的に時間と個人の資質の問題に帰結されるので。


> そうすれば、あと30年くらいしたら全世界中のC/C++で書かれたプログラムが誤作
> 動をするという2038年問題に、対応できると思います。(time_tを64ビット化すれば)

time_tを32ビット整数で定義しなければいけないという規格もなければ,1970年1月1日起算でなければいけないという規格もありません。
現実に,VC++2005付属ライブラリではtime_tは64bit整数型です。

でもって,現時点でtime_tが32ビット整数で動いているプログラムが存在する以上,そのプログラムが稼働している場合に問題はおきます。
# 2000年問題を考えてみれば,30年後に動いていることは予測がつきます。

tk-xleader

Re:参照について(C++)

#28

投稿記事 by tk-xleader » 18年前

あっ、そうなんですか。VC++2005ではもうすでにtime_tを64bit化したんですね。
という事はlong long int型にも対応しているのでしょうか?


> time_tを32ビット整数で定義しなければいけないという規格もなければ,1970年1月1日起算でなければいけな>いという規格もありません。

>現時点でtime_tが32ビット整数で動いているプログラムが存在する以上,そのプログラムが稼働している場合
>に問題はおきます。

ただ、time_tが32bitである環境があるというのは、現時点ではなんら問題はなくても。将来的には問題を
起こしますよね。time_tの64bit化を規格に盛り込む事で、そういった問題を抱えたプログラムを、できる
だけ少なくした方が、結果的にいい方向に物事が進むと思います。ただ、結局64bit化したとしても、また
そのオーバーフロー期限が迫ってきたら、同じような論議になるのでしょうが…。

組木紙織

Re:参照について(C++)

#29

投稿記事 by 組木紙織 » 18年前

>個人でC++のコンパイラを作る事

このことは多分私のせいだと思います。
c++の仕様が大きいことの比喩として聞いたことがあって、印象に残っていたので使ったのですが。

>2038年問題
が近づくと、急にプログラムの修正の仕事がたくさん入って儲かる。。。

ことになったらいいなと密かにおもっているのですが。


> しかし、STLというのはあまりにも大きすぎて理解するのに相当の時間がかかると思います

理解するだけならそんなに時間はかからない。
覚えて使えるようにするとなると時間はかかる。
実際に仕事で使うとすると、覚えることに無意味に時間をかけれないので、
必要な部分だけ覚えて、後は仕様書を見ながら使う。

といったことだろうと思います。
STLにはある特定の分野でしか使わない部分(complexなど)
も数多くあるので、STLのすべてを使ったことがある人はほとんどいないはず。
という意味ではリストやベクタなどの良く使うものだけを覚えておけば十分だと思います。

#仕様を全部覚えているのが理想だとは思いますが。

それに言語なんて目的のための手段でしかないので、C++が苦手な分野をわざわざC++で書かずに、
目的にあった言語を選択していくのがベストだと思います。

>将来的には問題を 起こしますよね。

プログラムに完全な汎用性を求めるとひどいことになる。
と私は思っています。
数値型だって多くの桁数が必要な場合から、(少し桁数が少なくても)2進数に置き換えた時の誤差を嫌う
場合、更に高速の更に高速を求めている場合もありますので。
同じ数値型といっても求められている機能は目的によってだいぶ異なります。

プログラムを作る場合は目的にあったプログラムを目的に沿って作るのが一番良いと
思っています。
そのことで言うと、
将来的に問題を起こすことが分かっていても、求められているプログラムの動作期間はそんなに長くないので
無視、あるいは簡単な警告を出すだけにしよう。
と決めてプログラムを作ることを、
将来的に正しく動作しないことが分かっていても、
将来っていつまで?という根本的な問題が入ってくるので、
否定出来ないと思います。

tk-xleader

Re:参照について(C++)

#30

投稿記事 by tk-xleader » 18年前

ただ、僕の場合は、とんでもなく恐ろしい事に64bitをこえる128bit整数のライブラリを作ろう
と思ったぐらいですから、ただ、設計段階でどう足し算を実装しようかでだいぶ悩み、結局の
ところ挫折してしまいましたが…。趣味なので挫折しようが、いくら時間をかけようが別に問
題は生じないので。そもそも中学生なので、結構ヒマが多いのでゆっくりとやっています。

YuO

Re:参照について(C++)

#31

投稿記事 by YuO » 18年前

> あっ、そうなんですか。VC++2005ではもうすでにtime_tを64bit化したんですね。
> という事はlong long int型にも対応しているのでしょうか?

long longは単に__int64の別名です。
# __int32はintの別名。
#include <iostream>
#include <typeinfo>
int main ()
{
    std::cout << typeid(long long).name() << std::endl;
    return 0;
}
というtest.cppについて,
>cl /EHsc test.cpp && test
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj
__int64
となります。


> time_tの64bit化を規格に盛り込む事で、そういった問題を抱えたプログラムを、できる
> だけ少なくした方が、結果的にいい方向に物事が進むと思います。

だから,time_tのサイズについての規定なんて全く存在しないんですってば。
ISO/IEC 9899:1999 or INCITS/ISO/IEC 9899:1999 or JIS X 3010:2003の7.23.1の第3段落を読んで下さい。
# JIS X 3010:2003ならJISC行けば一応PDFが読めます。

規格に文句言うなら,規格を読むくらいはしないと話になりませんよ。


> が近づくと、急にプログラムの修正の仕事がたくさん入って儲かる。。。
> ことになったらいいなと密かにおもっているのですが。

Y2Kの時よりも難儀そうですけどね……。
UNIXの今より古いカーネルコードを読んで,とか。

でも,特需はありそうです。
2038-01-19T12:13:00+09:00から67secのカウントダウンで,2038-01-19T12:14:10+09:00を過ぎたタイミングで,
・何事もなく,安堵のため息が漏れる
→本当に何も起こらず,帰りに一杯引っかけて買える組
→実はシステム時間が遅れていて,1分後くらいに不意打ちで来てあたふた組
 に分裂
・何か起こって,緊急対策状態へ移行
・実はシステム時間が早まっていてて,すでに緊急対策状態へ移行している
の4パターンに分かれそうですが。


> STLにはある特定の分野でしか使わない部分(complexなど)
> も数多くあるので、STLのすべてを使ったことがある人はほとんどいないはず。

complexはSTLに入れるものでしょうかね……。
まぁ,標準ライブラリでもcomplexは使い方のわかりやすいほうでしょうけれど,
<locale>とか,普通使わないようなライブラリは……。
# まぁ,codecvtとか趣味で使ったことありますが……<ICUとか使う方がどう考えても賢い。


> という意味ではリストやベクタなどの良く使うものだけを覚えておけば十分だと思います。

STLだとコンテナ系と<algorithm>くらいですかね。
とりあえず
・std::vector<T>
・std::map<K, V>
・std::for_each
・std::find
・std::copy
・std::remove
・std::sort
・std::swap
・std::accumerate @ <numeric>
あたりの基本的な使い方がわかれば,よいかな,と思います。
アルゴリズムで重要なのは,左閉右開区間の反復子を渡すことと,std::removeなどは実際には削除しないことくらいでしょうか。

ちなみに,私の使う「STL」という用語は,ISO/IEC 14882:2003中の
・20.3 Function objects
・23 Containers library
・24 Iterators library,
・25 Algorithm library
・26.4 Generalized numeric operations
で定義されるものを指しています。
# 26.4は時々入らないこともあるのですが……。


> ただ、僕の場合は、とんでもなく恐ろしい事に64bitをこえる128bit整数のライブラリを作ろう
> と思ったぐらいですから

多倍長整数演算のクラスなら,ネット上に沢山転がっていますよ。
# というか,Boostに無いのが不思議。
32bit + 32bit => 64bitができるのであれば,
64bit + 64bit => 128bitもほぼ同じ実装でできるはず。
以下同じ。
というわけで,そのあたりはtempalteを賢く使うことで解決できそうな感じです。

tk-xleader

Re:参照について(C++)

#32

投稿記事 by tk-xleader » 18年前

>というわけで,そのあたりはtempalteを賢く使うことで解決できそうな感じです。

テンプレートですか!?いったいどのように応用するのでしょうか。

また、time_tのサイズですが、フリーのBCC++ 5.5では4byteだったので、僕の今使っ
ているコンパイラでは、2038年問題にそのまま直面するので。かといってこのまま
ではVisual Studio 2005 AEを購入した意味がないのですが、今趣味でやっている
ゲーム製作を、購入する前に始めてしまったのが、この問題に直面したわけなので
す。なので、ただ、Windows APIでは時間関係の整数型を64bitになっていれば、まぁ
問題はないのですが………。

また、C++の利点を最大限に生かそうとするならば、やはりC++を全て網羅するとはい
きませんがそれくらい学習し身につけたほうがC++にとって最良の方法でのコーディ
ングなどが可能になると思うのですが。僕の場合はいろいろと何か身につけたほうが
いいかなと思って、このC++の世界に入って、勉強しているので…

Justy

Re:参照について(C++)

#33

投稿記事 by Justy » 18年前

 おっと、気が付けばスレが伸びてる・・・。


# YuOさん
というか,Boostに無いのが不思議
 非公式には boost::big_uintクラスなんてのがありました。
 でも何故か unsignedオンリー・・・。


# tkmakwins15さん
趣味でやっている ゲーム製作を、購入する前に始めてしまったのが
この問題に直面したわけなのです
 それはまたすごいね。
 2038年問題に引っかかる仕様のゲームを作ろうとしているわけですか。
 差し支えなければ教えて下さい。どういうゲームなのでしょうか?


Windows APIでは時間関係の整数型を64bitになっていれば
 WindowAPIの時間関連は年・月・日などがそれぞれ別変数になっているので、
理論的には60000年以上に対応できます。
 OSがきちんと正しい値を返すかどうかは別問題ですが。

http://support.microsoft.com/kb/436249/JA/

tk-xleader

Re:参照について(C++)

#34

投稿記事 by tk-xleader » 18年前

>おっと、気が付けばスレが伸びてる・・・。

確かに伸びてますね。このスレ入れて34件目なんですね…。これだったら
どっかでスレ分けるべきだったと後悔しています…。

>それはまたすごいね。
>2038年問題に引っかかる仕様のゲームを作ろうとしているわけですか。
>差し支えなければ教えて下さい。どういうゲームなのでしょうか?

内容は2DのRPGです。とりあえずこのまま作り、完成させてからVC++に移して
2038年問題に引っかからない仕様に、とりあえずする予定です。でも、そ
ういえば現在時刻の取得はCの time()でUTC取得→localetime()で日本時間
に直す作業をしなくても、Win32 APIのGetLocalTime()を使えば一発なんで
すよね…。また、time()を使うもう一つの訳は、プレイ時間の記録、というわ
けなのですけれども、これはtime_tがいくらオーバーフローを起こそうとも、
(2038年問題後も)次のようなコードは別に問題を起こさないんですよね↓
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;

int main()
{
	time_t start,finish;//処理を始めた時間と、処理を終えた時間の記録の変数
	int count;
	start = time();

	//10億回乱数を計算させる
	for(count=1;count<1000000000;count++){
		cout<<rand();
	}
	finish = time();
	cout<<(finish-start);
	return 0;
}
結局、いくらオーバーフローを起こそうとも、引き算をすると逆にオーバーフローを起こす
ので、正確な数値が得られるという事があるので、現在時刻の取得に32bitのtime_tさえ使
わなければ、まぁ大丈夫だと思います。あーでもclock()のほうがいいのかな? clock()の場
合はCLOCK_PER_SECマクロで割る必要があるのですよね。また、プレイ時間がintの上限を超
えた時の対策は、今のところ思いつかないので、これはまた、じっくりと考えていくつもり
です。あと、time_tを64bitにすると、西暦で3000億年弱まで正常稼動するそうです。これは
宇宙の歴史の20倍ほどであるそうなので(ウィキペディアより)、今よりもコンピューター
が強力になったり、intが普通に128,256…bitと実装されてもおかしくはないですから。
64bit化が、現時点での一番の解決法だと僕は思います。

ちなみにゲーム開発には山田 巧氏のDxライブラリを使用させてもらっています。ただし、
このライブラリの目的であるメッセージ処理の簡素化については、この目的に反して、
プロシージャを書いたりしていますが…。Win32 APIの練習もかねてやってますので。

Justy

Re:参照について(C++)

#35

投稿記事 by Justy » 18年前

内容は2DのRPGです
time()を使うもう一つの訳は、プレイ時間の記録、というわけなのです
プレイ時間がintの上限を超えた時の対策
 なるほど。
 ということであれば、その対策って本当に必要ですか?
 つまり、その頃までそのゲームを遊び続ける予定があるか、ってことですが。


次のようなコードは別に問題を起こさないんですよね
 Windowsの時計を 2038年にすればテストできますので実際にいろいろ試してみてはどうでしょうか。

tk-xleader

Re:参照について(C++)

#36

投稿記事 by tk-xleader » 18年前

よく考えてみればそこまで考える必要がないですね。int型の上限なんて
秒単位で記録しても、2038-1970として68→約60年分なので、こんなに長
い間同じゲームを同じデータでやり続ける人ってあまりいませんよね。

組木紙織

Re:参照について(C++)

#37

投稿記事 by 組木紙織 » 18年前

>テンプレートですか!?いったいどのように応用するのでしょうか。

こんなかんじでしょうか。確認などはしていませんが、感覚だけでもつかんでもらえたら。
符号なし整数型を使う場合しか考えていません。
template<typename U>
class Hoge
{
private:
	U num[2];
public:
	U operator+(U const & rhs);
};
template<typename U>
U Hoge<U>::operator+(U const &rhs)
{
	U out;
	out.[0] = this->num[0] + rhs.num[0]
	out.[1] = this->num[1] + rhs.num[1]
//桁上がり考慮
	out.[1] += (out.[0] < this->num[0] || out.[0] <  rhs.num[0]) ? 1:0;
	
	return out;
}
>ちなみに,私の使う「STL」という用語は
私は、単純に
C++の標準ライブラリのうちテンプレートを使うものをSTLと呼ぶと思っていました。

tk-xleader

Re:参照について(C++)

#38

投稿記事 by tk-xleader » 18年前

組木紙織さん::
これは足し算の実装なのですよね。とりあえず掛け算については、
これを掛ける数だけ繰り返す。というアルゴリズムで大丈夫だと
思うので…、しっかりと「多倍長整数」とググって見たらいろいろと
見つかって、それ参考にしながら作っています。

あと、長いプログラムを書こうと思ったら、僕の場合は、保守性を
考慮した上で、クラスを使ってのオブジェクト指向プログラミング
の効果を結構実感しています。特にゲームプログラミングでは、
機能毎にクラスを分けて、関係のありつつ、なおかつ機能を一つ
の関数でできるように、またベースとなる構造(骨組み)のクラスを
それから派生したクラスによって機能を強化していくというスタイ
ルは、結構保守性の向上に役立つと実感しています。(ゲームプロ
グラミングやりながらC++を使えるようになっている。今日ようや
く継承ができるようになった。)なので、C++はいい言語だと思いま
す。

YuO

Re:参照について(C++)

#39

投稿記事 by YuO » 18年前

> >テンプレートですか!?いったいどのように応用するのでしょうか。
> こんなかんじでしょうか。

うーん,違います……。
template <unsigned bit_size> class Hoge;
template <unsigned bit_size> struct HogeTraits
{
    typedef Hoge<bit_size / 2> BaseType;
};
template <> struct HogeTraits<64>
{
    typedef unsigned long BaseType;
};
template <unsigned bit_size> class Hoge
{
public:
    typedef typename HogeTraits<bit_size>::BaseType BaseType;
private:
    BaseType data_[2];
public:
    Hoge & operator+= (const Hoge & rhs)
    {
        if (std::numeric_limits<BaseType>::max() - data_[0] < rhs.data_[0]) {
            // 桁上がり
            ++data_[1];
        }
        data_[0] += rhs.data_[0];
        data_[1] += rhs.data_[1];
        return *this;
    }
};
一応,sizeは64以上で2の累乗でないといけなかったり,std::numeric_limitsの特殊化が必要だったりしますが,
# ついでにunsigned longが32bitであることも前提にしています。
こうやっておけばHoge<512>はHoge<256>を,Hoge<256>はHoge<128>を,Hoge<128>はHoge<64>を,Hoge<64>はunsigned longを,
それぞれ使って自動的に実装を生成してくれます。

組木紙織さんの方法では,Hoge<Hoge<Hoge<Hoge<unsigned long> > > >と書かないといけないので,使う側が大変です。


> >ちなみに,私の使う「STL」という用語は
> 私は、単純に
> C++の標準ライブラリのうちテンプレートを使うものをSTLと呼ぶと思っていました。

iostreamは通常STLに入れないですね。
std::basic_stringは微妙な線です。

ただ,STLという用語の範囲は人それぞれなので,自分の範囲を定義して提示しておかないと誤解を生む可能性を持っています。

組木紙織

Re:参照について(C++)

#40

投稿記事 by 組木紙織 » 18年前

YuOさま

これはまさしくテンプレートメタプログラミング。
私も現在勉強中ですが、なかなか難しくて大変です。

>template <> struct HogeTraits<64>

template <> struct HogeTraits<sizeof(unsigned long)>
とすれば
unsigned longが32であるという前提は、なくなるのですが、
今度は環境によって使える数字が違ったりする可能性が。
実際に使おうと思ったら変な数字を入れたらコンパイルエラーを出すようにしたほうがいいですね。

と思いますが、こんなのを作れるのは凄いです。

>これは足し算の実装なのですよね。とりあえず掛け算については、
>これを掛ける数だけ繰り返す。というアルゴリズムで大丈夫だと

実際にこのアルゴリズムを使うと、時間がかかるので、別のアルゴリズムを調べたほうが
いいと思います。
幸いにも調べたら他のアルゴリズムは出てくると思います。

tk-xleader

Re:参照について(C++)

#41

投稿記事 by tk-xleader » 18年前

>iostreamは通常STLに入れないですね

STLの定義とは何かという問題になるのですよね。C++の入出力
はiostreamを含むストリームによってしますが。この<<や>>は
数値、文字列、文字などの入出力に同じ要領で使えますし、ジ
ェネリックプログラミングの考え方がここにあるとしたら、
iostreamを入れるという考え方になると思いますし、アルゴリ
ズム、コンテナ、反復子によって定義される汎用データ型ライ
ブラリ。とするならば、iostreamはSTLではないという考え方
になると思いますが。ただ、C++のストリーム入出力をSTLとす
るのかは、正直僕にはわかりません。

閉鎖

“C言語何でも質問掲示板” へ戻る