C++相談室 part58

このエントリーをはてなブックマークに追加
934デフォルトの名無しさん:2007/11/09(金) 20:09:46
>>5のSGI-STLがおぬぬめ
935デフォルトの名無しさん:2007/11/09(金) 20:22:58
>>933
原著あるよ
936デフォルトの名無しさん:2007/11/09(金) 20:41:15
マクソのVisual Studio .NETタダ版を取ってくればSTLのマニュアルが見られる(英語)
937デフォルトの名無しさん:2007/11/09(金) 22:02:28
938デフォルトの名無しさん:2007/11/09(金) 22:42:32
MSDNライブラリをダウンロードしたりオンラインで見たりとか。
あとは検索性が難だが、JIS X 3014がJISCのWebサイトから見れる。
939デフォルトの名無しさん:2007/11/09(金) 22:56:01
なあ、下のクラスを-Wall -W -Weffc++でコンパイルすると、
なんかうるさい警告が山ほど出るけど、なんでだろ?

/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/allocator.h:
  In instantiation of `std::allocator<MyClass*>':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:79:
  instantiated from `std::_Vector_base<MyClass*, std::allocator<MyClass*> >::_Vector_impl'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:110:
  instantiated from `std::_Vector_base<MyClass*, std::allocator<MyClass*> >'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:142:
  instantiated from `std::vector<MyClass*, std::allocator<MyClass*> >'
main.cpp:52:
  instantiated from here

class MyClass {
  public:
    MyClass() {};
    virtual ~MyClass() {};
};
vector<MyClass*> myvec;

int
main()
{
  MyClass *p;

  p = new MyClass();
  myvec.push_back(p);
  return 0;
}
940デフォルトの名無しさん:2007/11/09(金) 23:18:00
スレチガイだったかもシレンが。。。

上記の警告を-Weffec++有効にしたままで抑制する方法ってあるんかな。
941デフォルトの名無しさん:2007/11/09(金) 23:37:02
よくわからないけど、STLはEffectiveC++スタイルでコーディングされていないってことなんじゃないの?
942912:2007/11/09(金) 23:53:17
>>915
>>907は確かに言葉が足りないと思うが、
安価先のレスを読めば意図を理解できるだろう。

それに比べて君は、君が馬鹿にしている>>906より言葉が足りない。
もう少し、人のいわんとすることを理解しようとする努力と、
人に伝えるための努力が必要だろう。 

まぁ、お前こそとっととチネがほんねだけれども。
943デフォルトの名無しさん:2007/11/10(土) 02:58:41
>>940
システムヘッダファイルからは警告を出さない、っていうオプションがあったような気がする
944デフォルトの名無しさん:2007/11/10(土) 10:24:53
>>943
システムヘッダから警告出さないのがデフォルトで、出せって言うオプションがある。

gcc がバグってたみたい。修正は、 4.2.x ?
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14172
945デフォルトの名無しさん:2007/11/10(土) 19:41:45
#include <iostream>

template< int N >
class class1
{
    public:
        void print()
        {
            std::cout<<"test"<<std::endl;
        }
};

template< int N >
class class2 :class1<N>
{
};

int main()
{
    class2<42> obj;
    obj.print(); //ここでコンパイルエラー
    return    0;
}

'class1<42>::print()' はアクセスできないとコンパイラに怒られます。
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19
と似たようなエラーであることは分かったので、
obj.class1<42>::print();とか
(class1<42>)(&obj)->print();とか試してみましたが、やはり怒られます。
どう解決すればよいのか教えていただければ幸いです。
946デフォルトの名無しさん:2007/11/10(土) 19:46:18
>>945
private継承だから?
947デフォルトの名無しさん:2007/11/10(土) 19:47:14
>>945
あなたが必要なのは
メンバ変数ですか?
それともテンプレートですか?
948デフォルトの名無しさん:2007/11/10(土) 19:53:45
>>946
すみません、そうでした。
しばらくjavaしかやってなかったものですっかりpublic継承忘れてました。

>>947
一応テンプレートです。
949デフォルトの名無しさん:2007/11/11(日) 23:50:02
void data_get(void** data);
こんなCの関数があって、これは俺が作ったものではないので変更できません。

typedef struct foo{
int a;
}foo;
こんな構造体があって、Cなら
foo *f;
data_get(&f);
こんな風に使います。

C++で今までVisual C++ 2005 で開発してこの関数を使うとき
foo* f;
data_get(reinterpret_cast<void**>(&f));
とやっていて、動作も特に問題が無かったのですが、g++4.1でコンパイルしたところ
warning: dereferencing type-punned pointer will break strict-aliasing rules
と怒られました。

一応この警告の意味とコードが標準に準拠してないことは理解したつもりですが
それでは、data_get関数をC++から安全に使うにはどのようにしたらいいでしょうか?

foo* f;
void** tmp = reinterpret_cast<void**>(&f);
data_get(tmp);
としてもも警告が出てしまいます。

void* tmp;
data_get(&tmp);
foo* f = reinterpret_cast<foo*>(tmp);
これだと警告が出ないのですが、大丈夫でしょうか。
950デフォルトの名無しさん:2007/11/11(日) 23:52:14
>>949
void* tmp; 
data_get(&tmp); 
foo* f = static_cast<foo*>(tmp); 

の方がいいんじゃない
951デフォルトの名無しさん:2007/11/11(日) 23:56:02
>>949
reinterpret_cast は良くないね。最後のやつを static_cast に変えるのが最善かな。
952デフォルトの名無しさん:2007/11/12(月) 00:02:30
>>949
C++なんだから、こっちで多重定義してしまえばいい。
inline foo_data_get(foo*& data)
{
void *p;
data_get(&p);
data = static_cast<foo*>(p);
}
953949:2007/11/12(月) 00:32:02
ありがとうございます、>>950>>952で行こうと思います。
ところで、void*からのキャストはreinterpret_castもstatic_castも同じだと思ってたんですが
違うんですか?
954デフォルトの名無しさん:2007/11/12(月) 00:33:34
>>953
reinterpret_cast は実装依存。 static_cast は foo* → void* への暗黙の変換の逆変換。
どっちも同じになる実装がほとんどだろうけどね。
955デフォルトの名無しさん:2007/11/12(月) 00:37:09
暗黙の変換を明示的に行うのがstatic_castだってeffective C++に書いてあった
956デフォルトの名無しさん:2007/11/12(月) 02:12:17
>>955
それだけではないけどね
void* -> T* の暗黙の変換はないけど
これもstatic_castの仕事の一つ
957デフォルトの名無しさん:2007/11/12(月) 08:10:10
test.cxxというファイル名だと、
__FILE__がtest.cxxになりますが、

#define test.cxx

と同等のことを__FILE__を使ってできませんか?
958デフォルトの名無しさん:2007/11/12(月) 08:48:00
>>957
識別氏にピリオドを含むことはできません。定義するマクロ名にマクロ展開の結果は使えません。
959デフォルトの名無しさん:2007/11/12(月) 22:55:33
>>949
g++ -fno-strict-aliasing じゃだめ?
960デフォルトの名無しさん:2007/11/13(火) 01:17:34
>>949
C++もCと同じだと思うけど、
汎用(void)のポインタへのポインタ型というのは規格上ないはず。
void func(void **);
int *p;
func((void **)&p);
こういうコードは移植性がなく動作は未定義。
正しくは、
void *vp = p;
f(&vp);
p = vp;

なので自分で書いてるとおりvoidポインタを介在させればよい。
foo *f;
void *tmp = f;
data_get(&tmp);
f = static_cast<foo*>(tmp);
でいいんでは?

961デフォルトの名無しさん:2007/11/13(火) 02:43:06
>>960
void**という型がないわけではない。
ただ、T**――Tはvoid以外の任意の型(あー、一応関数型も除く)――
とvoid**との間の変換が定義されていないだけ。
962デフォルトの名無しさん:2007/11/13(火) 03:39:21
グローバル変数の定義順序について質問させてください。

--- values.cpp ---
int values[] = { 5, 1, 2, 4, ... };

--- values.h ---
extern int values[];

--- table.cpp ---
#include "values.h"
int table[] = { values[0], values[1], values[2], ... };

こんな風に、異なる翻訳単位に2つのグローバル変数
values[] と table[] があって、table[] の初期化が values[] に
依存しているときに、コンパイラはこの依存関係(?)をちゃんと
検出してグローバル変数の定義順序を決めてくれるもんなんでしょうか?
詳しい方おられましたら、よろしくお願いします。
963デフォルトの名無しさん:2007/11/13(火) 03:44:08
定義した順に初期化される。
table.cppは int table[]... の前に extern int values[]; を展開する。
964962:2007/11/13(火) 03:44:24
すみません、このサンプルで御願いします…。

--- values.cpp ---
int values[] = { 5, 1, 2, 4, ... };
int get_value(int i) { return values[i]; }

--- values.h ---
int get_value(int);

--- table.cpp ---
#include "values.h"
int table[] = { get_values(0), get_values(1), get_value(2), ... };
965デフォルトの名無しさん:2007/11/13(火) 03:47:15
x定義した順に初期化される。
o宣言した順に
966デフォルトの名無しさん:2007/11/13(火) 03:47:57
自分でコンパイルしろよカス
967デフォルトの名無しさん:2007/11/13(火) 03:59:33
宣言した順ということは、どちらの翻訳単位が先に翻訳されるか
によって変わるということでしょうか。

手元のコンパイラ BorlandC++BuilderX でどちらも試してみましたが、
警告もエラーもなく期待通りに初期化されるようなので、良く分かりません。
table[] の初期化が values[] の初期化より先に行われるようなコンパイラが
あるとすれば、問題が起こるかもと思ったのですが。
968デフォルトの名無しさん:2007/11/13(火) 08:12:18
>>964
その場合 values は定数式で初期化されているので静的初期化になります。
table は定数式じゃないので動的初期化になります。非ローカルオブジェクトの
初期化は静的初期化が先で動的初期化が後なので、その例だと問題は起こり
ません。

静的初期化には特に順番というものがありません。動的初期化については
同じ翻訳単位内での順番は定義順と決まっていますが、翻訳単位をまたぐと
順番が定まらなくなりますので、その場合に問題が起こる可能性があります。
969949:2007/11/13(火) 08:20:18
>>959
それやったら負けかなと思ってる。
「最適化しても良い」って決まりですし。

>>960-961
ふむふむ、
そういえなvoid**はvoid*とは違って全然汎用ではないですね
970デフォルトの名無しさん:2007/11/13(火) 08:53:01
>>969
そりゃそうだ、void **はvoid *へのポインタに過ぎない。
971デフォルトの名無しさん:2007/11/13(火) 09:41:55
>>966
実行速度を計測するのと違って、自分の環境でたまたまうまくいけば
それで疑問が晴れる、というものではないから、それは見当違いの反応だよ。
972デフォルトの名無しさん:2007/11/13(火) 10:15:24
>>961
>>969
汎用(void)はおかしかった。void**がないわけではなく
”汎用として使えるポインタへのポインタ型はない”
と言いたかった。ここでいう汎用とはあるT型から
の変換とT型への変換ができるということ。
(不完全型へのポインタなので変換できない)

詳しくはCプログラミングFAQ
973デフォルトの名無しさん:2007/11/13(火) 10:25:43
教えてください。

void *vp;
があったとして
*vpのようにデリファレンスすることはできませんが
void** vpp;
があったとして、これを*vppのようにデリファレンスするのはOK
ですよね?(*vppはただのポインタで結果はvoid*となるので)

974973:2007/11/13(火) 10:27:03
訂正
(*vppはただのポインタで結果はvoid*となるので) ×
(vppはただのポインタで*vppの結果はvoid*となるので) ○


975973:2007/11/13(火) 10:40:19
念のため確認させて欲しいのですが

void MyMemoryAlloc(void **vpp, size_t n)
{
 .
 . 詳細は省略
 .

 *vpp = malloc(n * sizeof(T)); //確保したメモリへのポインタ

}

T *p;
void *vp = p;
MyMemoryAlloc(&vp, 10);
p = vp;

というのはOKですよね?というかよくありますよね?
976デフォルトの名無しさん:2007/11/13(火) 11:05:02
>>973
おk

だけど
>>975

T *p;
MyMemoryAlloc(&p, 10);

これでよくね?
ただし、TがPOD型のみ有効。
977デフォルトの名無しさん:2007/11/13(火) 11:26:56
is_podは現行のC++ではあまり使えないらしいし怖いのぅ
978973:2007/11/13(火) 11:45:20
>>976
ご説明ありがとうございます。

T *p;
MyMemoryAlloc(&p, 10);
としてしまうと、>>961さんご指摘のように
T** から void**への暗黙の変換が
できないですよね?
(POD型というのが分からなかったのですが。)
979デフォルトの名無しさん:2007/11/13(火) 14:44:25
>>968
ありがとうございます。勉強になりました。
>>962のサンプルの場合も、table[] の初期化子 (values[0] など)は
定数式ではない(配列の要素は const であっても定数式にならないん
でしたよね) ので、やはり values が table より先に(静的)初期化される、
と考えて良いんですね。
980デフォルトの名無しさん:2007/11/13(火) 15:22:00
>>978

あまり深く考えずに、

template<typename T> T * vp_assign( T * & lhs, void * rhs){
 return lhs = static_cast<T *>(rhs);
}

template<typename T> T * vpp_assign( T ** lhs, void ** rhs) {
 return vp_assign(*lhs, *rhs);
}

とか作って、それを使えばいいじゃまいか
981デフォルトの名無しさん:2007/11/14(水) 02:37:14
>>379
そうだよ。規格の 3.6.2 ね。
982981:2007/11/14(水) 02:37:59
盛大にアンカーミスった。 379 じゃなくて >>979 ね。
983デフォルトの名無しさん
>>975
p = vp はコンパイルできない。 static_cast が必要。

>>976
void** の引数に T** は渡せない。

>>980
意味が分からないから、たぶんやめたほうがいい。