トップページ⇒tech
1001コメント388KB

【C++】template 統合スレ -- STL/Boost/Loki, etc.

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
C++ のジェネリックプログラミングの話をしましょう。
以下のスレッドを統合するスレです。

STLスレッド
Part1 http://pc.2ch.net/tech/kako/1004/10042/1004287394.html
Part2 http://pc3.2ch.net/test/read.cgi/tech/1026793823/

【C++】Boost使い集まれ!
http://pc3.2ch.net/test/read.cgi/tech/1033830935/

Generic Programming with C++ Template
http://pc.2ch.net/tech/kako/1008/10085/1008593126.html

関連スレ、その他リンクは >>2-5 あたりに。
0209デフォルトの名無しさんNGNG
>>208
メンバ関数テンプレートはtと同一のスコープの時は
大丈夫ですが、パラメータとしてtをどこかへ渡すと
t.template と書く必要があります。
0210デフォルトの名無しさんNGNG
>>209
大丈夫なようですが・・・・・意味を勘違いしてるかな?

struct Test {
template <typename T, typename U>
void func(T x, U y) {
std::cout << typeid(x).name() << ' ' << typeid(y).name() << std::endl;
}
};

void abc(Test& t)
{
t.func(1, 1.1);
}

int main()
{
Test t;

abc(t);
}
0211デフォルトの名無しさんNGNG
>>210
あんまり適当なことを言うのもあれなんで識者の人に
聞きたいところだけど、
基本的には型推論できるところは.templateは要らないと思った。
http://pc.2ch.net/tech/kako/1008/10085/1008593126.html
に書いてあったんだけど、900番台がなぜか抜けてるんだよね。。。

これ以上は分りません。すんまそん。
0212デフォルトの名無しさんNGNG
>>210
わざわざすみません。いろいろ実験してみたら、下のエラーとコメントしてある
行で、'<'がどうも比較演算子とコンパイラが勘違いしてエラーになるようです。

こういう場合、template限定子を付けて、後に続く'<'が型名のパラメータの
始まりである事を示さなければならないようです。

まだよくわかってないのですが、さらに実験してみます。

struct Test {
template <typename T, typename U>
T test(U x) {
std::cout << typeid(T).name() << ' ' << typeid(x).name() << std::endl;
return static_cast<T>(x);
}
};

template <typename T>
T abc(T x)
{
Test t;
T y;
// y = t.test<T>(x); // エラー
y = t.template test<T>(x);
return y;
}

int main()
{
abc(1.1);
}
0213デフォルトの名無しさんNGNG
スマソ>>211さんに対してのレスです。
0214デフォルトの名無しさんNGNG
>>212
それはコンパイラのバグだと思う…。

> template <typename T>
> T abc(T x)
> {
> Test t;
> T y;
> y = t.test<T>(x); // エラー

だと t の型はtemplateパラメータ T に依存せずに決定しているので、
わざわざ template 限定子を入れる必要はないはず。t の型が T に
依存するなら、test がメンバ関数 template であることはパース時には
わからんから、明示的な template 限定子が必要になるけれど。

例えばもし
> template <typename Y>
> struct Test {
で
> T abc(T x)
> {
> Test<T> t;
だったら、tの型がTに依存するので、必要。
0215デフォルトの名無しさんNGNG
漢字のテクスチャを管理するデータ構造を作りたいです。
機能と優先順位は
1.内部で管理しているテクスチャのハンドル数が最大数を超えたら最も古いハンドルを開放する。
2.sjisのコードを指定するとデータ構造からテクスチャのハンドルを検索して返す。
3.ハンドルが存在しなければその時点でテクスチャを生成してそのハンドルを返す。
で、要素の構造体はこんな感じです。
struct{
unsigned short Code; /// 文字コード
void *Handle; /// テクスチャハンドル
};

要するにキャッシュの機構なんですがとりあえず
hashでインスタンスを、queueで参照を管理するというのを
思いついたんですが他に効率的な方法はありますか?
0216bloomNGNG

http://www.agemasukudasai.com/bloom/
0217デフォルトの名無しさんNGNG
>>214
いろいろやってみたけど、templateパラメータは現れた順に解決される
みたいですね。

コンパイラはgcc3.2(MinGW)を使ってみたんですけど、やっぱりバグです
かね。プログラミング言語C++第3版§C.13.6、P971を読んでいたら、メンバ
テンプレートの型の推定が不可能な場合、メンバ関数名の次に現れる
"<"を比較演算子と見なしてしまいコンパイルエラーになるような事が
書いてありました。

でもそのような事はまれなので、エラーが生じた場合のみtemplate限定子
を付けるようにしようと思います。
0218デフォルトの名無しさんNGNG
>>204
オソレスだが、次のようにするとVC7でも分割できる。

--- T.h ---
template <typename T>
void print(const T&);

--- T.cpp ---
#include <iostream>
#include "T.h"

template <typename T>
void print(const T& t)
{    std::cout << t << std::endl; }

template void print<int>(const int&);

--- main.cpp ---
#include "T.h"

int main()
{
   int i = 10;
   print(i);

   return 0;
}
0219デフォルトの名無しさんNGNG
> template void print<int>(const int&);

template にする意味あんまりないじゃん。
0220204NGNG
>218
ありがとうございます。動きました。

この場合、T.cpp をコンパイルする際には、実際の利用時の型を T.cpp 内部で明確にし、
それぞれの型別動作をオブジェファイルに記述している。と考えていいんですよね。

main 部に { double d ; print d } を追加するとリンクできないが、
T.cpp に template void print<double>(const double&); を記述すると正常動作したので、
このように解釈しました。
0221デフォルトの名無しさんNGNG
>>219
たしかに、語源的な意味しか残ってないわな。

>>220
おおむね合ってます。「明示的なインスタンス化」っていうやつですわ。
0222デフォルトの名無しさんNGNG
ソースファイル
↓
プレコンパイル
↓
ソース内包オブジェクトファイル
↓
リンク
↓
ソース内包リンクドモジュール
↓
ポストコンパイル
↓
ロードモジュール

という方式にすれば、export 対応はそんなに難しくないと思うんだけど・・・。
0223デフォルトの名無しさんNGNG
>222
簡単に逆コンパイルできちゃうような代物だと、そもそも export 使う意味が無いと
思うんだが。速度の話なら pre compiled header って手もあるわけだし。
0224デフォルトの名無しさんNGNG
export って逆コンパイルと何か関係あるの?
0225デフォルトの名無しさんNGNG


でさ、、、、

どれが一番速いの?
0226デフォルトの名無しさんNGNG
何の話?
0227デフォルトの名無しさんNGNG
どのライブラリが一番効率よいかってこと。

0228デフォルトの名無しさんNGNG
STLport 4.5.3をVC6sp5で使おうと思ってインストールしたんですが、
BoundsCheckerがSTLportのアロケータ(たぶん)みたいなところで
メモリリークを検出してくれます。

#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
  std::string hello = "Hello, world!";
  std::cout << hello << std::endl;
  return 0;
}
こんなコードでも1600バイトのリークが検出されます。
_STLP_USE_NEWALLOCマクロを使えば出なくなるんですが、遅くなりそうだなー
ってのと、Configuration Manualに

When using tools like Purify (c), Codeguard (c) or BoundsChecker (c),
it is advised to #define _STLP_USE_MALLOC or _STLP_USE_NEWALLOC,
otherwise pointer checking will generally not be available on most STL
internal structures, thus defeating the purpose of those tools.

とあるので気にしなくていいってことなんでしょうか?
0229デフォルトの名無しさんNGNG
>228
気にするな。
0230デフォルトの名無しさんNGNG
>>228

実際STLportのdefault allocatorは一度確保したら絶対返さない。

> とあるので気にしなくていいってことなんでしょうか?

時と場合で気にしたりしなかったり

allocatorつかったらmallocされっぱなしでも困らないならそのまま

返してくれなきゃ困る場合はSTLP_USE_MALLOCとか
自前でallocator用意すれ
0231デフォルトの名無しさんNGNG
Effective STLなかなか良さげ
0232学習能力の無い人NGNG
mapにconst reference operator[]() constって
何で無いの?
毎回const map作って[]使おうとすると怒られるから
constはずすってことをつい繰り返しちゃうんだけど・・・。
0233デフォルトの名無しさんNGNG
>>232
std::mapの[]演算子は、対応するキーがないと、自動的に挿入する仕様になって
いるから。その時点で既にconstでは無い。

[]が便利な事は認めるが、できるだけfindとinsertを使おう。例えばstd::multimapには
[]演算子が無い。仕様をよく考えると当然だが、最初この事を知ったとき、STLには
設計ミスがあるのではないかと思ってしまった。
0234デフォルトの名無しさんNGNG
対応するキーがないと自動的に挿入する、という機能が欲しい時に [] を使わない
理由があるの?
0235デフォルトの名無しさんNGNG
>234
効率。
0236デフォルトの名無しさんNGNG
>>235
コード量が増える割には、見合った効果が得られないけど?

初期要素 500,000、試行回数 5,000,000 で試してみた。
挿入が全く発生しない状況でも、1 % 程しか遅くならない。
挿入しか発生しない場合は 5 % 程遅い。

それとも、漏れの書き方が悪い?

int r = large_rand();
map<int, int>::iterator itr = m2.find(r);
if(itr == m2.end())
itr = m2.insert(pair<int, int>(r, 0)).first;
return itr->second;
0237デフォルトの名無しさんNGNG
つーか、233 の 「例えば」 の前後が繋がってないよ。
0238デフォルトの名無しさんNGNG
236のコードを見て気が付いたが、
find,insertではコピーコンストラクタが呼ばれて
[]演算子だとデフォルトコンストラクタが呼ばれた後に
=演算子が呼び出されるんだな。

だからintではなくもっと複雑な型じゃないと差は出ないのかも。

逆に、find,insertでは二回検索するので余計に遅くなりそうな気がするのだが
236の結果を見るとそうでもないのが不思議。
0239237NGNG
>>238
> find,insertでは二回検索するので余計に遅くなりそうな気がするのだが

漏れも最初そう思ったけど、find が意外に速いんだよね。
ちなみに、[] の実装はこうだったよ。

_Tref operator[](const key_type& _Kv)
{
 iterator _P = insert(value_type(_Kv, _Ty())).first;
 return ((*_P).second);
}

つまり、236 のコードの、if より下と全く同等。
だから、テストでは find のミスヒット分だけ遅くなったという事だね。

> find,insertではコピーコンストラクタが呼ばれて
> []演算子だとデフォルトコンストラクタが呼ばれた後に
> =演算子が呼び出されるんだな。

上に示した通り共通の動作をしているので、これは違うと思う。
0240238NGNG
スマソ、勘違いしてた。
何を思ったか[]演算子を使う方に

m2[r]=0;

みたいなコードを想像してた。
これじゃ動作が違うのに。
0241デフォルトの名無しさんNGNG
>>239
そんなタコな実装ねぇだろ。
その実装だと、
・二回検索することになる
・挿入しない場合にも一時オブジェクトの生成・破棄がおこなわれる。
0242239NGNG
> そんなタコな実装ねぇだろ。

VC6 に付属の STL をそのままかっぱらってきたんだが・・・。
ところで、どこが 2 重検索になるって?
0243241NGNG
ほんとだ>VC6
おそろしい。

あ、二回検索にはならねぇな。
236と脳内ブレンドされてたよ。スマソ
0244デフォルトの名無しさんNGNG
* Copyright (c) 1994
* Hewlett-Packard Company
だと、
Allocator<T>::reference operator[](const key_type& k) {
 return (*((insert(value_type(k, T()))).first)).second;
}
だな。
まぁ、なんだ。たしかに簡潔といえば簡潔だが……
0245デフォルトの名無しさんNGNG
std::mapのoperator[]は特異な存在だけど、便利であるがゆえによく使う。
0246デフォルトの名無しさんNGNG
コードがかさばってでも速い方がいいというなら、C++ を使う理由はない。
0247デフォルトの名無しさんNGNG
STLportのstd::bit_vectorと、Boostのboost::dynamic_bitsetの使い分けは
どのようにされていますか?
0248デフォルトの名無しさんNGNG
コードがかさばっても速さと汎用性が両立できるなら、C++を使う理由になる。
0249デフォルトの名無しさんNGNG
> 汎用性

何の話?
0250デフォルトの名無しさんNGNG
>249
スレの趣旨から言って Generic プログラミングだろう(違うか)
0251デフォルトの名無しさんNGNG
vc++ver7.0でもtupleは使えない。ok?
0252デフォルトの名無しさんNGNG
#include<string>
using namespace std;

template <typename T> struct dd :public T
{
typename typedef dd<T>::value_type char_type;
inline friend operator<(const dd<T>& a1,const dd<T>& a2 ); //(1)
inline friend operator<(const dd<T>& a1,const char_type* a2 );//(2)
dd(){}
~dd(){}
dd(const char_type* a){ *this=a;}
};

template <typename T> bool operator<(const dd<T>& a1,const dd<T>& a2 )
{
return ((const T&)a1 < (const T&)a2);
}

template <typename T> bool operator<(const dd<T>& a1, const dd<T>::char_type* a2 )
{
return ((const T&)a1 < a2);
}

int main()
{
dd<string> D("abc"),D2("efg");
D < D2; //(1) OK
D < "abc"; //(2) NG
}
templateのoperatorで
(2)のような場合、実装をクラスの中に書くしかないのでしょうか?
0253デフォルトの名無しさんNGNG
修正:
dd(const char_type* a)
{
static_cast<T&>(*this)=a;
}
ですね。
追記:
friendなんだからクラス内に実装を書けということなのか、
friendの行を削除したらOKでした。
0254デフォルトの名無しさんNGNG
テンプレートクラスはfriendをメンバに取ることはできないね。
0255デフォルトの名無しさんNGNG
しまった、テンプレートクラスもfriendはメンバに取れるね。逝ってくる・・・
0256デフォルトの名無しさんNGNG
>>252>>253
うまくいったよ。ddのコンストラクタはexplicit宣言しておかないと、(1)や(2)で
勝手にstd::operator< が選ばれて警告が出る。

template <typename T>
struct dd : public T {
typedef T value_type;
typedef typename dd<T>::value_type char_type;
friend bool operator< <T>(const dd<T>& a1, const dd<T>& a2); //(1)
friend bool operator< <T>(const dd<T>& a1, const char_type* a2);//(2)
dd() {}
explicit dd(const char* a){
static_cast<T&>(*this) = a;
}
~dd() {}
};
0257デフォルトの名無しさんNGNG
template <typename T>
inline bool operator<(const dd<T>& a1,const dd<T>& a2)
{
return ((const T&)a1 < (const T&)a2);
}

template <typename T>
inline bool operator<(const dd<T>& a1, const typename dd<T>::char_type* a2)
{
return ((const T&)a1 < a2);
}

int main()
{
dd<std::string> D("abc"), D2("efg");
D < D2; //(1) OK
D < "abc"; //(2) OK
}

friend宣言で未解決のテンプレートパラメータがあると、非テンプレート関数として
コンパイルされてしまうらしいから、型特定して警告を回避した。
0258デフォルトの名無しさんNGNG
でもまだおかしいや。(2)が実行されてないようです。

template <typename T>
struct dd : public T {
typedef T value_type;
typedef typename dd<T>::value_type char_type;
friend bool operator< <T>(const dd<T>& a1, const dd<T>& a2); //(1)
friend bool operator< <T>(const dd<T>& a1, const typename dd<T>::char_type* a2);//(2)
dd() {}
explicit dd(const char* a){
static_cast<T&>(*this) = a;
}
~dd() {}
};
0259デフォルトの名無しさんNGNG
template <typename T>
inline bool operator<(const dd<T>& a1,const dd<T>& a2)
{
std::cout << "dd<T> < dd<T>" << std::endl;
return ((const T&)a1 < (const T&)a2);
}

template <typename T>
inline bool operator<(const dd<T>& a1, const typename dd<T>::char_type* a2)
{
std::cout << "dd<T> < dd<T>::char_type" << std::endl;
return ((const T&)a1 < a2);
}

int main()
{
dd<std::string> D("abc"), D2("efg");
D < D2; //(1) OK
D < "abc"; //(2) OK、しかし実行されない?
}
0260デフォルトの名無しさんNGNG
>>259
基底クラス(std::string)の operator<(const std::string&, const char*) が
呼ばれているようだな
通常の関数とテンプレート関数が多重定義されている場合、通常の関数が
優先されるからな
0261デフォルトの名無しさんNGNG
継承したクラスのオブジェクトは自分自身を指すのだね。
template <typename T> struct dd :public T
{
typedef typename dd<T>::value_type char_type;
friend bool operator<(const char_type* a1, const dd<T>& a2 )
{
cout << "(3) m_str ->"<< a2.m_str << endl;//何も表示されない!!
return (a1 < (const T&)a2);
}
dd(){m_str="2ch";}
~dd(){}
explicit dd(const char_type* a)
{
dd::dd();
static_cast<T&>(*this)=a;//なんとm_strにaが入る
}
private:
string m_str;
};
0262続きNGNG
template <typename T> bool operator<(const dd<T>& a1,const dd<T>& a2 )
{
cout << "(1)" << endl;
return ((const T&)a1 < (const T&)a2);
}
template <typename T> bool operator<(const dd<T>& a1, const typename dd<T>::char_type* a2 )
{
cout << "(2)" << endl;
return ((const T&)a1 < a2);
}
int main()
{
dd<string> D("abc"),D2("efg");
D < D2; //(1) OK
D < "abc"; //(2) OK
"abc" < D; //(3) OK
}
0263デフォルトの名無しさんNGNG
>>261
>cout << "(3) m_str ->"<< a2.m_str << endl;//何も表示されない!!
m_str は初期化時の空文のままだから、表示されないのは当たり前。
>static_cast<T&>(*this)=a;//なんとm_strにaが入る
そんなわけね〜だろ!

なんか、バカでっかい勘違いしてんぞ

0264引き篭もりNGNG
レベルたけぇ・・・(-_-)
0265デフォルトの名無しさんNGNG
int main()
{
dd<std::string> D("abc"), D2("efg");
D < D2; //(1) OK
D < std::string("abc";) //(2) OK
}

のように、sts::stringの一時変数を作って渡してやらないと、テンプレート関数
の方を呼んでくれない。この当たりがテンプレートの限界なのか。
0266デフォルトの名無しさんNGNG
しかし、ちょっと疑問なのだが、

explicit dd(const typename dd<T>::char_type& a){
static_cast<T&>(*this) = a;
}

これって一体どこに代入しているの?どうみても自分自身に代入しているように
しか見えないのだが・・・・・どんな意味があるのだろう。
0267デフォルトの名無しさんNGNG
基本的な質問です。
More Effective C++のp.16、l2に実際のプログラムでは、このようなクラスはテンプレートになるのだが、
とあります。具体的にはどのように書けばいいのでしょうか?
0268デフォルトの名無しさんNGNG
>>266
なんか激しく気持ち悪い書き方だなぁ。
*(static_cast<T*>(this)) = a;
あるいはすなおに
T::operator=(a);
と書いたほうがわかりやすくないかい?
0269デフォルトの名無しさんNGNG
>>267
たんに、要素の型を int きめうちじゃなくてテンプレート引数で
指定できるようにすべきだ、ってことじゃないの?
0270デフォルトの名無しさんNGNG
>>268
というか、素直にこうだろ〜
explicit dd(const typename dd<T>::char_type& a) : T(a) { }
0271デフォルトの名無しさんNGNG
266です。
>>268>>270 やっはりそうですよね。分かりやすく書くことを心がけるようにします。
0272デフォルトの名無しさんNGNG
dd::dd();//このあとすぐにdd::~dd()が呼ばれてるみたい。
static_cast<T&>(*this)=a;//だからm_strは空白になってる。
なんかすごい勘違いしてたな。絶対変だと薄々思ってたけど...

コンストラクタからコンストラクタを呼ぶと直後にデストラクタが呼び出されるのか。

struct A :public string
{
string m_str;
A()
{
m_str="2ch";
cout << "A::A()" << endl;
}
~A()
{
cout << "A::~A()" << endl;
}
A(const char* c) :string(c)
{
A::A();
cout << "A::A(const char*)"<< endl;
}
};

int main()
{
A a("stu");
}


0273デフォルトの名無しさんNGNG
>>272
ちょっと違う。A::A(); と書くと、コンストラクタを呼び出したことにはならない。
単にAの一時変数が作成されてすぐに破棄されるだけ。

明示的にコンストラクタを呼び出すには、コンストラクタ初期化子を使う
しかない。
0274デフォルトの名無しさんNGNG
>A(const char* c) :string(c)
これ、: m_str(c) の間違いではなくて?
こういう書き方あるの?
0275デフォルトの名無しさんNGNG
>>273
なるほど!

>>274
A は stringを継承して、メンバも持っているから...。

A(const char* c) :string(c),m_str("m_str")
{
cout << static_cast<string>(*this) << endl;//stu
cout << m_str << endl;//m_str
}
0276デフォルトの名無しさんNGNG
明示的に呼ぶ場合、
this->A::A();
これならOKなのでは?
0277デフォルトの名無しさんNGNG
>>276
エラーっしょ。
0278デフォルトの名無しさんNGNG
>>277
できるよ。


#include <iostream>

using namespace std;

struct clsA
{
clsA(){cout<<"clsA():"<<hex<<(unsigned int)this<<endl;}
clsA(int){cout<<"clsA(int):"<<hex<<(unsigned int)this<<endl;
cout<<"CASE:clsA::clsA()"<<endl;clsA::clsA();
cout<<"CASE:this->clsA::clsA()"<<endl;this->clsA::clsA();}
};

void main(void)
{
clsA a(int());
}
0279デフォルトの名無しさんNGNG
>>278
コンパイラは何を使った?Borland-C++5.6.2及びgcc3.2(MinGW)は
エラーが出て通らないけど。
0280278NGNG
>>279
そうなの?
VC5(苦笑)でつ。
M$オンリーの機能なのか?
エラーはどんなの?
0281デフォルトの名無しさんNGNG
>>280
BCC5.6.2の場合。
エラー E2316 constructor2.cpp 12: 'clsA' は 'clsA' のメンバーではない(関数 clsA::clsA(int) )

gcc3.2(MinGW)の場合。
C:/MinGW/Learn/constructor2.cpp: In constructor `clsA::clsA(int)':
C:/MinGW/Learn/constructor2.cpp:12: parse error before `;' token

というエラーです。
0282278NGNG
>>281
わざわざTHXです。
…う〜ん。いよいよM$の仕様のような気が。
参考書引っ張り出してもう一度調べてみマフ...
0283デフォルトの名無しさんNGNG
>>282
俺も調べてみるが、確かコンストラクタからコンストラクタを呼び出すには、
初期化リストしか方法がなかったように記憶しているが・・・・どうだったっけな
0284デフォルトの名無しさんNGNG
>>282
どっかのメーリングリストではVC固有の機能だと言われてたな。

>>283
ちょっと話は変わるけど、こんなのどう?

static_cast<T*>(this)->~T();
new(this)T(param);

newで例外が起きるとヤバイが。
0285デフォルトの名無しさんNGNG
>>284
newの配置構文ですね。この場合、デストラクタは自分で呼び出してやらないと
いけないですね。
0286デフォルトの名無しさんNGNG
>>285
だから直前に呼んでるみたいだが
0287デフォルトの名無しさんNGNG
>>285
そうか? 
この場合、Tは(*this) の型の基底クラスだろ
この型のデストラクタがデフォで ~T() 呼ぶから
大丈夫だと思うんだが、どうよ

>>286
ちょっと、目の付け所がいまいち
0288デフォルトの名無しさんNGNG
>>287
そっか。そう言われればそうだな。途中でリコンストラクトした事にはコンパイラ
は気づいてないだろうからね。
0289デフォルトの名無しさんNGNG
>>269 ありが�d
0290デフォルトの名無しさんNGNG
>>284
× new(this)T(param);
○ new (static_cast<T*>(this)) T(param);
0291デフォルトの名無しさんNGNG
// こんな感じ?
#include <iostream>
using namespace std;

struct Base {
 Base() {
  cout << "Base::Base()" << endl;
 }
 virtual ~Base() {
  cout << "Base::~Base()" << endl;
 }
};

struct Ero : public Base {
 Ero() {
  cout << "エロ::エロ()" << endl;
 }
 ~Ero() {
  cout << "エロ::~エロ()" << endl;
 }
 Ero(int) {
  Base::~Base();
  new(this) Ero();
  cout << "エロ::エロ(int)" << endl;
 }
};

void main() {
 Ero ero(0); // エロ(0)
}
0292デフォルトの名無しさんNGNG
>>291
実行結果が次のようになったのだが、大丈夫だろうか?

Base::Base()
エロ::~エロ() //←これヤバくない?
Base::~Base()
Base::Base()
エロ::エロ()
エロ::エロ(int)
エロ::~エロ()
Base::~Base()
0293デフォルトの名無しさんNGNG
>>291
// ぜんぜん違うぞ、こうだ
#include <iostream>
class Foo
{
   int m;
public:
   Foo(int n = 0) : m(n)
   {   std::cout << "Foo is created by " << n << std::endl; }
   int val() const { return m; }
   ~Foo()
   {   std::cout << "Foo is destroyed. m = " << m << std::endl; }
};

template <typename T> class Bar : public T
{
public:
   Bar (int n = 0)
   {
       std::cout << "Bar is created by " << n << std::endl;
       static_cast<T*>(this)->~T();
       new (static_cast<T*>(this)) T(n);
   }
   ~Bar()
   {   std::cout << "Bar is destroyed." << std::endl; }
};

int main()
{
   Bar<Foo>(10);
}
0294293NGNG
今気づいたが、
テンプレート使う必然性無く、まったくレス違いなネタのような……
0295デフォルトの名無しさんNGNG
>>293
ををををぉぉぉぉなんとトリッキーな。

Fooのインスタンスが先に生成されるのが意外だったけど、これは使えそうだね。
0296291NGNG
>>292
やばいです。
つーか、うち(VC7)ではこうなりました。
仮想関数テーブルの取り出し方が違うのでしょうか?

Base::Base()
Base::~Base()
Base::Base()
エロ::エロ()
エロ::エロ(int)
エロ::~エロ()
Base::~Base()

>>293
飛び入りな者でスミマセン。
0297デフォルトの名無しさんNGNG
>>296
>>292はBorland-C++5.6.2です。
gcc3.2(MinGW)でやったら、次のようなエラーが出てコンパイルできませんでした。

C:/MinGW/Learn/constructor3.cpp: In constructor `Ero::Ero(int)':
C:/MinGW/Learn/constructor3.cpp:20: cannot call destructor `Base::~Base'
without object
0298デフォルトの名無しさんNGNG
gcc3.2(MinGW)は次のようにしたらコンパイルできて、実行結果は以下の通りです。

Ero(int) {
this->Base::~Base(); // thisから呼び出すようにした
new(this) Ero();
std::cout << "エロ::エロ(int)" << std::endl;
}

Base::Base()
Base::~Base()
Base::Base()
エロ::エロ()
エロ::エロ(int)

コンパイラによって実行結果がバラバラですね(^_^;)。
0299デフォルトの名無しさんNGNG
昨日から Modern C++ Design 読み始めたがなんだか
出じゃブーが多いなあ。
0300デフォルトの名無しさんNGNG
Phoenix Singleton とかな(藁
0301デフォルトの名無しさんNGNG
>>298
>コンパイラによって実行結果がバラバラですね(^_^;)。
データレイアウトの違いが原因かも(根拠なし)
0302デフォルトの名無しさんNGNG
>>300
300getしてるよ。
2〜3年前に似たようなこと頑張って考えてた時期あった。
基本型とユザ定義型の区別とか。
コンパイル時のじゃなくて実行時に区別するやつ。
ただしおれは目的があくまでパズルだった。
実用にしようと思ってたらなんか結果出てたかな...?
0303デフォルトの名無しさんNGNG
これって、メモリリークしちゃうの?
しないですよね?
void foo() {
    std::vector<std::string> v;
    v.push_back( *(new std::string("お兄ちゃん♥") );
}
0304デフォルトの名無しさんNGNG
Clear()
{
  for(std::vector<std::string>::iterator it=v.begin(); it!=v.end, ++it)
    delete &(*it);
  v.clear();
}

とかやらないと駄目なんじゃない?
0305デフォルトの名無しさんNGNG
>>304
(*it)はnewで作成したstringを
コピーコンストラクタでコピーした物だからダメだと思うが。
0306303NGNG
>>304-305
えっと、つまり、
void foo() {
string* p;
std::vector<std::string> v;
v.push_back( *(p = new std::string("美幸...おまえ...") );
delete p;
}
ってやらなきゃだめ、ってことですか?
0307デフォルトの名無しさんNGNG
>>306
そのコードだと、↓といっしょだな。
void foo() {
std::vector<std::string> v;
v.push_back( "美幸...おまえ..." );
}
0308303NGNG
うん、えっと、std::vectorが、
「なにを保持してるのか、どう扱えばいいのか」を知りたかっただけなのです。
そか、307見たいに書けるって事は、
「std::vector::push_backは、引数を基にして、
変換コンストラクタかコピーコンストラクタで新しいインスタンスを作って、
そのインスタンスを保持する」
ってことだよね。

新しいインスタンスを保持するんだから、
元のインスタンスは自分で解放する必要がある、と。

やっと心のもやもやが。ありがとうでした。
■ このスレッドは過去ログ倉庫に格納されています