C++相談室 part23

このエントリーをはてなブックマークに追加
952894:03/10/18 23:32
>>949
937の例でいうと、char buf[]の先頭がアライメントを意識して置かれていない可能性があるのが問題です。
>>952
static void* operator new(size_t) を適切に定義しておけ。
>>953
もうオマエは黙ってろよと、見当違いもいい加減にシロ

と894は思ってるよ、多分
>>951
意味がわかりません。
仮に、「それ」が「コンパイラの制限」だとしたら、
「普通に sizeof(A) 分のバッファ確保しとけば placement new 出来る」ことになるのですか?
956894:03/10/18 23:48
>>953
それで逃げる手が一つですね。ただしその場合は、Elm側からAにアクセスするたびに
必ずアライメント計算をしなくちゃならなくなります。

あ、もちろんbufのサイズは max(sizeof(A), sizeof(B))+アライメント分
にしておかないとダメです。

とりあえず
struct X {
char a;
char buf[8];
};
struct Y {
char a;
union {
char buf[8];
double d;
};
};
のsizeofでも見て、Y.dにアクセスしたい時の事を考えてみて下さい。
>>941
A とか B の placement new を、アライメント意識して書けば良いだけだと思うが……。
デフォルトだと「渡されたアドレスそのまま」返すことになってるけど、別にオフセット
調整しても良いんだし。

いちいちクラス毎に placement new 実装するのがダサイって話だと、そもそも
アライメント調整必須な段階で placement じゃない new も書き直す必要がある
(全部の処理系とはいわないが gcc 3.x とかはそう) から、手間は変わらないよ。
自動変数や static 変数だと、コンパイラ・リンカがよろしく取りはからってくれるけど、
new 使うとなると自前で工夫するのは大前提。
じゃあ、bufの前にintでもおいて、alignmentを意図すればいいじゃないか。
あるいは、charでなく、intでbufを確保する手もあるし。
え?なんでstatic void* operator new(size_t) を適切に定義することが回避方法になんの?

char buf[5454];
new(buf) A;

としてもその再定義したnewは呼ばれないぞ?
>>959
たぶん引数に void* を書き忘れてるんだと思うが。
>>958
世の中には8バイトアライメントや16バイトアライメントを必要とするものがあるのだよ
>>961
なら char を 7 つとか 15 とか挟んどけ。
963894:03/10/18 23:56
>>957
see 956
>>958, 962
see 912

>>959
その通りでした。文脈で明らかにplacement newの話だと思ったので
そう思い込んで返事しました。
>>962
アフォですか?
>union的に扱えればずっと楽なのでそういうのないかなぁと。

結局、「ない」ってのが答えだろ。
>>895-965 みたいなのを全て考えた上で boost::variant が
あるんだから、素直に使うかせめてソース読むかしようよ…
と思うんだがどうか。 1.31に入ることは確定してるから待つんでもいいが。 >>907
>>963
そもそも 894 の段階で、A, B が特定のアライメントを要求するなら、暗黙の Buf::new(size_t) を
使って new Buf できなくなってるワケだが……。
968894:03/10/19 00:23
>>966
おっしゃる通りです。私も別にboost::variantを使わないつもりはないのでそうします。
boostがどうやって回避してるか非常に興味深いし。

途中で「どうしてplacement newじゃダメなの?」とか言われたから
「まぁそういう疑問を持つ人も居るのかな?」とか思って返事したまでで。
特にゴネてるつもりはなかったんですが…

>>967
これ本当?unionなら大丈夫でしょ?そう信じて今まで書いてきたんだけど…
969937:03/10/19 00:30
お前らが騒いでる間に任意のアラインメントに対応できるコード書いた。
長いのでどっか貼り付けてくるからまってれ。
>>968
> これ本当?unionなら大丈夫でしょ?
処理系・ライブラリ依存だと思うが、俺の環境 (gcc 3.2 にベンダーがローカルな
パッチを当てたもの) だとダメだった。new Buf すると、単に

void *p = ::operator new(sizeof(Buf))

でヒープからメモリを持ってきて、この p をオフセット調整なしで使う。

だから 32byte aligned なメモリが欲しければ Buf クラスの operator new を自前で
定義して 32byte aligned なメモリを持ってくるように書き直す必要がある。

自動変数ならばコンパイラがスタックフレームポインタ調整を入れるし、static, global
変数はリンク時にリンカがメモリを適切に割り当てるから問題ないんだけど。
>>970
それは単に class A と class B にアラインメントが必要ないからではなかろうか。
>>971
そんなことはない。ちょうど先日はまった話なんだが

class Foo {
  u_char buf[1024] __attribute__((aligned(64))); // このメンバ変数は 64 バイトアライメント
};

といったクラスを用意して new Foo したら、buf か必ずしも 64 バイトアライメントされずに
困った。

アセンブラコードを出力させて調べたら >>970 みたいな状況だったので、Foo クラス内に

static void* operator new(size_t n) { return memalign(64, n); }
// memalign は指定したアライメントでヒープからメモリを切り出す関数

と追加して事なきを得た次第。
973937:03/10/19 00:55
http://do.sakura.ne.jp/~junkroom/cgi-bin/megabbs/readres.cgi?bo=lounge&vi=999294620&res=107

仮想関数の無いクラスのアラインメントは最初のプリミティブのアラインメントと等しいという仮定を置いてます。
>>972
PS2でつか?

struct aligned_t{};
namespace{ aligned_t aligned; }
void *operator new(size_t size,aligned_t,size_t n) {
return memalign(n,size);
}

int main(){
int *p=new(aligned,64) int;
}

こういう解決方法はどう?
>>974
> int *p=new(aligned,64) int;
それも良いアイデアだと思うけど、うっかり new(aligned, 64) Buf すべきところを new Buf しても
コンパイル時に検出できないのが悲しい。

C++ だと、ランタイムエラーよりはコンパイルエラーの方が何かと幸せだから。
CISCの派生CPUしか使った事がない
人ばかり見たいですね。このスレは。
でもその派生CPUでも高速化のためには
必要なんですけどね。
アライメント調整。
普通に struct A, struct B と

const int MAX_SIZE = Max<sizeof(A), sizeof(B)>::Value;
struct Buffer
{
enum{BUFFER_SIZE = MAX_SIZE / sizeof(int) + 1};
int buf[BUFFER_SIZE];
}

とか定義しといたら、A も B も Buffer もその先頭が
アライメント境界にくるように自動的に調整されないの?

調整されるんだったら、Buffer 型の配列作っといて、
それのアドレスを placement new に渡せば問題ないんじゃないの?
>>975
mallocで確保したメモリがどんなアライメント要求も満たすのが前提だから、
dlmallocにアライメント設定してmalloc置き換えるようにリンクさせればいいんじゃない?
>>977
Buffer はアラインメント境界に来るけど、それが A や B にとっても正しいとは限らない。
>>977
それだと、ふつうはintのアライメントを満たしてるだけだろな。
981894:03/10/19 04:34
>>970-972
ぐは。そうなんですか。かなりショック。
mallocにはアライメントは無理だってのは知ってたけど、
C++はせっかくnewに型渡してるのに意味ないじゃん。

情報ありがとうございました。
とりあえず週明けにstroustrup本にでも仕様を聞いてみますかねぇ。家にはない…
>>981
禿本には gcc の独自拡張である __attribute__ が載っているのか?
>>978
> mallocで確保したメモリがどんなアライメント要求も満たすのが前提だから、

処理系が知っているオブジェクトに対してはね。
__attribute__((aligned(64))); なんて物まで考慮に入れられないだろ。きりがない。
つーか、入れられても困るし。
>>981
> C++はせっかくnewに型渡してるのに意味ないじゃん。
そもそもユーザが明示的にアライメントを指定するのは、ANSI C++ 規格の範疇から
外れてるから。

ANSI C++ だと new Foo で呼ばれる operator new の型が

void* operator new(size_t n);

と決まっているので、アライメント値を渡す余地がない。
>>975
private: static void* operator new(size_t);
でOK?
>>985
それなら

public: static void* operator new(size_t n) { return memalign(64, n); }

で良いような気が。
次スレだぁ〜
>>988ゲットだぜ〜
>>989到着〜
>>990ハァハァ到着ぅ〜
なに〜先越されたーーーーー
おれがスレ立てるからおまいらは、待っててください。
このまま頂上目指すのみ
まだ見ぬ次スレへのリンクが紫色なのなんでだろぉ
それはおとズレた事があるから
998v(^・^)v:03/10/19 15:55
では閉じますか
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。