自前でnewのような関数を作っています。
mallocで確保したメモリ領域のそれぞれの項目に対してコンストラクタを呼び出したいのですが、
テンプレートで指定されたクラスのコンストラクタを明示的に呼ぶにはどうしたらよいですか?
テンプレート関数でなく、特定のクラスに対するものならできたのですが、
テンプレートで一般的に対応しようと思った所で躓きました。
また、deleteのほうは意図通り実装できました。
struct HOGE{
HOGE(){}
};
//特定のクラスに対するものは正常
HOGE *mynew(size_t len){
HOGE *v = (HOGE*)malloc(len * sizeof(HOGE));
for(size_t t = 0; t < len; ++t){
//v[t].HOGE();//error C2274: '関数形式のキャスト' : '.' 演算子の右側で使用できません。
v[t].HOGE::HOGE();//OK
}
return v;
}
template<typename T>
T *mynew(size_t len){
T *v = (T*)malloc(len * sizeof(T));
for(size_t t = 0; t < len; ++t){
v[t].T::T();//error C2039: 'T' : 'HOGE' のメンバーではありません。
//代わりに以下のように書いてみたが若干危険で効率も悪そう
T tmp = T();
memcpy(v + t, &tmp, sizeof(T));
memset(tmp, 0, sizeof(T));
}
return v;
}
template<typename T>
void mydelete(T *v, size_t len){
for(size_t t = 0; t < len; ++t){
v[t].~T();//OK
}
free(v);
}
HOGE *h = mynew<HOGE>(3);//NG
HOGE *j = mynew(3);//テンプレート関数でない方は呼べる
mydelete(j, 3);//OK
No.4ベストアンサー
- 回答日時:
placement newを十分理解していないようですね。
C++で未初期化の領域に対して、明示的にコンストラクタを呼び出す方法は、placement new以外にはありません。
やりたいことは以下のようなものではないでしょうか
template<typename T>
T *mynew(size_t len){
T *v = (T*)malloc(len * sizeof(T));
for(size_t t = 0; t < len; ++t){
new(&v[t]) T();
}
return v;
}
この回答への補足
返事がおそくなってすいません。
なるほど、外部で確保したポインタを渡すことで、newをコンストラクタを呼び出すためだけに使うということですね。
newの構文が複雑なので、単にコンストラクタを呼ぶというテンプレート関数にして、mallocの部分と分離してしまった方がわかりやすそうです。
この方法をとってみようと思います。
placement newの記事を探しているうちに、当初の「渡されたポインタをそのまま返すnew」を知らずに、後から知られた使い方「任意の引数を渡せるnew」を先に知ってしまい、それを自分で定義しようとしてごちゃごちゃになっていたようです。
newをインクルードして教えていただいたコードが実行できました。
ありがとうございました。
No.3
- 回答日時:
> テンプレート関数でなく、特定のクラスに対するものならできたのですが、
本当ですか?
> v[t].HOGE::HOGE();//OK
これは何をしているのか、ちゃんと理解していますか。
No.2
- 回答日時:
「これでおおよそ目的が果たせそうなのですが、operator new[]とoperator delete[]は定義できたのですが、operator newとoperator deleteはすでに定義されてるとでて、オーバーライド(?)できませんでした。
」と書かれていますが, operator new や operator delete が突然出てきているのはなぜでしょうか?
元の質問を読む限り, 「グローバルのnewとdeleteを置き換える」必要などないはずですが.
いずれにしても, エラーメッセージは正確に書いてほしいし, 「どう書いたらどこでどのようなエラーが出たのか」を秘密にするようならまともな答えが返ってこない可能性は理解してほしい.
この回答への補足
placement newを調べるとoperator newにたどり着きました。
グローバルのnewとdeleteを置き換えたときに出たエラーはヘッダにかいて__inlineを付け忘れていたため、定義の重複でした。すいません。
void *operator new(size_t sz){ return malloc(sz + 1); }
error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) は既に inlineCheck.obj で定義されています。
グローバルなnewを置き換えたい理由は以下です。
1 要求された個数よりも1要素分余分なバッファを確保する
2 要求された個数分の要素に対して確保時にコンストラクタを、破棄時にデストラクタを呼ぶ。余分に確保された1要素分にはコンストラクタもデストラクタも呼ばず、0で埋める
3 intやコンストラクタを持たないオブジェクトは、未定義値ではなく0で埋める
グローバルな一般的なnewを置き換えるのは、ライブラリを使うときに混乱するので、いろいろ調べた結果、余分な引数を持ったnewがあることを知ったので、それをつかって目的が果たせそうです。
(通常のnewではvoidと要求されたサイズだけが渡され、1要素分のサイズがわからなかったが、余分な引数を持つnewでそのサイズが渡せた)
//配列の最後に要素0を追加して返すnull terminated new
void *operator new[](size_t tsz, size_t tsz2){
tsz += tsz2;
unsigned char *v = (unsigned char*)malloc(tsz);
for(size_t t = 0; t < tsz; ++t){
v[t] = 0;
}
return v;
}
void operator delete[](void *v, size_t tsz2){
free(v);
}
template<typename T>
T *ntnew(size_t tlen){
return new(sizeof(T)) T[tlen];
}
template<typename T>
void ntdel(T *v){
delete[] v;
}
No.1
- 回答日時:
1st choice は placement new か.
あるいは適当に typename を追加する?
この回答への補足
ありがとうございます。
placement newについて調べた所、自前定義のnewが呼び出された後、勝手にコンストラクタを呼んでくれるようです。
また、自前のdeleteが呼び出される前に、勝手にデストラクタを呼んでくれるようです。
これでおおよそ目的が果たせそうなのですが、operator new[]とoperator delete[]は定義できたのですが、operator newとoperator deleteはすでに定義されてるとでて、オーバーライド(?)できませんでした。
グローバルのnewとdeleteを置き換える方法はありませんか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
(UWSC) 「#32770」の意味わかり...
-
DataGridViewのセルに斜線を引...
-
FriendとPublicの違い。。。
-
オーバーライド関数の呼び出し...
-
エディットコントロールでEnter...
-
既定のコンストラクタがない?
-
MFCのドラッグ&ドロップについて
-
DebugクラスとTraceクラスの違い
-
C++.NETのWindowsフォームで自...
-
OnInitDialog()の関数の組み込み方
-
メンバ変数のサイズの増加
-
C#で定数クラスをシングルトン...
-
VC++ 7.1 で メインウィンドウ...
-
C++で継承元のクラスの代入演算...
-
openFrameworks-複数台Arduino...
-
このコンパイルエラーの意味に...
-
[MFC]メッセージボックス内にメ...
-
イベントにAddHandlerされてい...
-
【ASP.NET】 独自で作成したク...
-
VC++ リストボックスにデータを...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
FriendとPublicの違い。。。
-
既定のコンストラクタがない?
-
(UWSC) 「#32770」の意味わかり...
-
クラスのアドレスを引数として...
-
ダイアログ表示時にチェックボ...
-
エディットコントロールでEnter...
-
イベントにAddHandlerされてい...
-
【ASP.NET】 独自で作成したク...
-
DebugクラスとTraceクラスの違い
-
MFCのCListCtrlでスクロールを検出
-
C++ protectedにアクセス不可
-
C++で継承元のクラスの代入演算...
-
継承したクラスを、継承元のク...
-
OnInitDialog()の関数の組み込み方
-
ダイアログクラスのコントロー...
-
MessageBoxを継承したい
-
DataGridViewのセルに斜線を引...
-
このコンパイルエラーの意味に...
-
MFCアプリのコマンドラインでパ...
-
C#のクラス設計について教えて...
おすすめ情報