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

C++相談室 part85

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2010/10/09(土) 20:22:35
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレに
お願いします。

前スレ
C++相談室 part84
http://hibari.2ch.net/test/read.cgi/tech/1284736187/
0052デフォルトの名無しさん2010/10/11(月) 15:51:14
辻褄合わせに必死の言語なんだから、深い事は考えてはいけない。
純粋仮想デストラクタの(中身空の)定義も書いてやればいい。

class a {
virtual ~a() = 0;
};
a::~a() {}
0053デフォルトの名無しさん2010/10/11(月) 15:52:27
IEnumerableオブジェクトが勝手に定める順序で列挙されるでいいんじゃなイカ?
ランダムだろうと気分だろうと勝手に定めた順序だ
0054デフォルトの名無しさん2010/10/11(月) 15:53:14
>>53
誤爆です。すみません
0055デフォルトの名無しさん2010/10/11(月) 15:56:55
unique_ptrからshared_ptrへの変換は安全なのでしょうか。

std::unique_ptr<std::wstring> GetName();
のような関数があって、普通は戻り値のunique_ptrをそのまま
使えばいいのですが、vectorに入れたいケースがあり、shared_ptrに
変換したく、次のようなコードを書きました。

std::vector<std::shared_ptr<std::wstring>>> vec;
std::shared_ptr<std::wstring> str = GetName();
vec.push_back(str);

こういう書き方って安全なんですか?
unique_ptrの一時オブジェクトが作られ、それからshared_ptrへのムーブが
暗黙のうちに行われているので安全ではないか、と考えているのですが。
0056デフォルトの名無しさん2010/10/11(月) 15:57:47
>>51,52
できました!ありがとうございます!
この場合これを継承した派生クラスが消滅した場合、
この抽象クラスのデストラクタは実行されないんですかね?
0057デフォルトの名無しさん2010/10/11(月) 16:10:13
>>55
VC10でソース見たけど、shared_ptrにunique_ptrの右辺値参照する代入演算子が定義されてるね。
OKのようだね。
これは便利だ。ありがたく使わせてもらうよ。
0058デフォルトの名無しさん2010/10/11(月) 16:59:09
というかその程度の機能すら持ってなかったら標準ライブラリとして使い物にならないよ
0059デフォルトの名無しさん2010/10/11(月) 17:59:45
もっとも、unique_ptrをvectorの要素にすることだって可能だよ。
0060デフォルトの名無しさん2010/10/11(月) 19:33:47
>>59
unique_ptrならauto_ptrと違ってvectorそのものの動作に問題はないんでしょうけど、
要素を取り出すとき、つまらないミスをしそうですね。
暗黙のムーブを発生させちゃって、vectorには無効なunique_ptrが残ることに。
0061デフォルトの名無しさん2010/10/11(月) 19:46:27
……と思ったけど、>>55 が可能なのは GetName() の戻り値が右辺値たり得るからですね。
vector から要素を取り出すときは常に左辺値になるから、そんな心配はいらないのか。
0062デフォルトの名無しさん2010/10/11(月) 19:52:15
明示的にムーブしない限りは大丈夫じゃない?
0063デフォルトの名無しさん2010/10/11(月) 19:57:38
auto x = vec.front();
とかやって「先輩!コンパイルできません!」と泣きついてくる奴はいそうな気がする。

auto &x = vec.front();
「こうすれば大丈夫だよ」と理由や副作用も含めて教えてあげればいいんだが、

auto x = std::move(vec.front());
こういうやり方を教えて「こうすればコンパイルできるみたいだよ」なんて言う奴は
ウチの会社にはいないはず……うん、いないはず……
0064デフォルトの名無しさん2010/10/11(月) 20:23:16
>>55-63
それを説明するには、lvalueとrvalueの区別をきっちり説明しなくちゃいけないな。
俺自信ない。
0065デフォルトの名無しさん2010/10/11(月) 20:53:10
03ですら使わせてほんとに大丈夫かっていう連中がそこかしこにいるのに
0xになってさらに混乱しそうな仕様がいくつも追加されても困るよな
まあ業務では0xコンパイラ使わなきゃいいだけって話だけど
0066デフォルトの名無しさん2010/10/11(月) 20:57:13
98ならおkってわけでもないんだろ?
Javaでもやらせとけ
0067デフォルトの名無しさん2010/10/11(月) 21:10:25
ようするにC++は玄人の玩具的な扱いが加速しすぎているんだよ
もっと仕様を軽量化単純化したC++Liteを作るべき
0068デフォルトの名無しさん2010/10/11(月) 21:13:56
Embeded C++ ゴゴゴゴゴゴゴゴ・・・
0069デフォルトの名無しさん2010/10/11(月) 21:18:42
>>67
いちいちアレが使えてこれが使えなくてとか確認することになるぜ
余計ややこしくするだけだっての
他の言語かC使えばいいんだよ

>>68
組み込みもやってるけど一度も使った事ないわそれw
0070デフォルトの名無しさん2010/10/11(月) 21:34:17
> いちいちアレが使えてこれが使えなくてとか確認することになるぜ

今現在そのような状況なのを何とかしてほしいってことだろ
関数テンプレートの部分初期化とかリンカがコンパイラを呼び出したりとか
0071デフォルトの名無しさん2010/10/11(月) 21:52:50
>>68
わらたw
0072デフォルトの名無しさん2010/10/11(月) 21:58:14
けどC++は何でもありってのは良いところでもあると思うんだけどな
自分のグループやプロジェクトではそれなりにルール決めると良いだろうが
たまに Java 使うと窮屈に感じてしょうがない
0073デフォルトの名無しさん2010/10/11(月) 22:16:07
C++ で配列の要素数を求めるテンプレート作りたいのですが、

template <class T, int N>
int length(const T (&x)[N]) {
  return N;
}


const BYTE* ptr = &values[0];
inr length = length(ptr);

とすると
error C2784: 'int length(const T (&)[N])' :テンプレート 引数を 'const T (&)[N]' に対して 'const BYTE *' から減少できませんでした

とエラーが出てしまいます。
どうすればいいのでしょうか?
0074デフォルトの名無しさん2010/10/11(月) 22:20:31
>>73
const BYTE* ptr これ配列じゃないよ
0075デフォルトの名無しさん2010/10/11(月) 22:24:40
length(values)
ぷっ
0076デフォルトの名無しさん2010/10/11(月) 22:29:27
>>74 すみません。

void hogehoge(const BYTE *values)
{

なんです。

void hogehoge(const BYTE values[])
{
にしても、C2784エラーがでてしまいます。
0077デフォルトの名無しさん2010/10/11(月) 22:31:14
>>76
そのhogehogeもテンプレートにしちゃいないよ。
0078デフォルトの名無しさん2010/10/11(月) 22:31:17
それも配列ではないよ
0079デフォルトの名無しさん2010/10/11(月) 22:33:22
>>76
だめだこりゃ!
0080デフォルトの名無しさん2010/10/11(月) 22:46:43
void hogehoge(const BYTE& values)
{

こうですか?
0081デフォルトの名無しさん2010/10/11(月) 22:47:49
素直に vector 使え
もう大分前から STL は C++ 標準
0082デフォルトの名無しさん2010/10/11(月) 23:04:56
関数を沢山作ると、関数の並び方によって見やすさが変わると思います
void print1();
void print2();
void print3();
の方が
void print3();
void print1();
void print2();
より見やすい気がする

お前らはどんなルールで関数を宣言していますか?
0083デフォルトの名無しさん2010/10/11(月) 23:07:59
世界最高峰のプログラマーだが、そんなこと気にしたことないね。
書けるとこに書けばいい。
スレ違いだから。
0084デフォルトの名無しさん2010/10/11(月) 23:08:06
>>82
両方とも醜いです
0085デフォルトの名無しさん2010/10/11(月) 23:45:08
>>92
printを使うのは良いとして 1,2,3 なんてイミフなラベル付けないなぁ
0086デフォルトの名無しさん2010/10/11(月) 23:45:56
処理される順に書くか対になるものを並べるかは迷うことが多い

init → begin → end → free か
init → free → begin → end
0087852010/10/11(月) 23:46:01
あんかー間違えた。すまん >>92 → >>82
0088デフォルトの名無しさん2010/10/11(月) 23:48:07
説明しやすいように連番使っただけでそこをgdgd言うのは単なる揚げ足取りだろう・・・
0089デフォルトの名無しさん2010/10/11(月) 23:48:13
単なる関数名の例にケチつけるとはさすが
0090デフォルトの名無しさん2010/10/12(火) 00:53:21
辞書順だろ
結局はこれが一番一覧性高い
0091デフォルトの名無しさん2010/10/12(火) 00:59:38
>>82
それぞれどんな機能差があるか分からないけど、番号だけで分けるなんて安易で酷いと思うよ
0092デフォルトの名無しさん2010/10/12(火) 01:02:47
>>88-89
説明のためだけなら、実用における
void print1();
void print2();
void print3();
と
void print3();
void print1();
void print2();
の違いがさっぱり分からないわけだが。
0093デフォルトの名無しさん2010/10/12(火) 01:05:00
>>82
宣言とか定義場所の並び順なら、グループ別に分けてコメントで見出しと説明文とgrep用の印付ける。
その上で呼び出し順序のある物ならその順番で書いて、そうじゃない単位での並び順はそんなわらわら増えた事も無いし適当。
0094デフォルトの名無しさん2010/10/12(火) 01:14:12
>>92
辞書順の例を出しただけ。
他にどんなルールで並べてるのかを聞いてるんだよ
0095デフォルトの名無しさん2010/10/12(火) 01:16:17
想像力の欠乏した奴が多いなw
0096デフォルトの名無しさん2010/10/12(火) 01:53:40
>>94
というか辞書順という言葉が分からなかったんだろ?
0097292010/10/12(火) 06:16:30
>>30
>valarrayの - 演算子って定義されてるの?
演算子いっぱい定義されてます.
http://www.cplusplus.com/reference/std/valarray/valarray/operators/


>>31
遅延評価をやってるってことですよね?
doSomething(std::valarray<float>(A - x));
でも
doSomething(A -= x);
でもコンパイル通りました.ありがとうございます!
(言い忘れましたが私はgcc 4.5を使っています)

ただ,なぜ自動的に型変換されないのでしょう.
std::valarrayのコンストラクタにA-xは渡せるのだから引数に渡るとき暗黙に型変換されるものだと思っていましたが・・
0098デフォルトの名無しさん2010/10/12(火) 06:55:39
1,2,3だけで辞書順であることを想像しろと言われてもなぁ。せめてA,B,Cにしろよ。
0099デフォルトの名無しさん2010/10/12(火) 08:24:34
>>80
テンプレート配列
#include <iostream>

template<class T,int N>
inline int length(T (&a)[N])
{
return N;
}

int _tmain(int argc, _TCHAR* argv[])
{
int s[70];
std::cout<<length<>(s);
return 0;
}
0100デフォルトの名無しさん2010/10/12(火) 08:42:14
誰かSleepをしない、fps計測コードを貼ってくれませんか?
お願いします。
0101デフォルトの名無しさん2010/10/12(火) 09:14:18
もういいです
0102デフォルトの名無しさん2010/10/12(火) 09:34:56
答えようかと思いましたがもういいならいいです
0103デフォルトの名無しさん2010/10/12(火) 09:53:50
fps=フレーム数/経過時間
0104デフォルトの名無しさん2010/10/12(火) 18:29:31
>>101
これは私ではありません
0105デフォルトの名無しさん2010/10/12(火) 19:41:08
>>97
私も気になって調べてみましたがよくわかりませんでした。
valarrayの_Exprを受け取るコンストラクタがメンバテンプレートなのが関係あるかも?
0106デフォルトの名無しさん2010/10/12(火) 19:47:56
ご質問させてください。

class Test {
public:
  Test() { c = 'T'; i = 10; };

  char getChar() { return c; };
  int getInt() { return i; };

private:
  int i;
  char c;
};

int main()
{
  Test t;

  printf("t.i = %d, t.c = %c\n", t.getInt(), t.getChar());
  printf("t = %d\n", t);

  return 0;
}

としたとき、1つ目のprintf()関数で値を取得出来るのは分かるのですが、
2つ目のprintf()関数でも、最初に定義されたメンバ変数の値(つまりt.getInt()と同じ値)が
取得出来るようです。

値を書き換えることは出来ないとは言え、実質privateメンバ変数の値に
publicメンバ関数を通さずにアクセスできていることになりますが、
これは言語仕様でしょうか?
0107デフォルトの名無しさん2010/10/12(火) 19:56:57
>>106
printfの正しくない使い方をして先頭のメンバーがたまたま見えてるだけ。
仕様としては未定義な動作。
0108デフォルトの名無しさん2010/10/12(火) 19:58:59
>>106
具体的な仕様は知らんのだけど、それってprintfの中で (int)t されてるんじゃないかな。
0109デフォルトの名無しさん2010/10/12(火) 20:00:18
>>107
言語仕様うんぬんではなく、printf()の正しくない使い方だったのですね。
迅速なご回答ありがとうございました。
0110デフォルトの名無しさん2010/10/12(火) 20:07:42
>>108
ありがとうございます。

インスタンスtの先頭にメンバ変数iが割り当てられて、
printf()内で(int)tされた結果、tのアドレスをint型として扱い
iの値が出力されたということでしょうか?
0111デフォルトの名無しさん2010/10/12(火) 20:13:36
>>110
そんな所だと思う。
int a = *(int*)&t;
printf("%d\n", a);
でも同じ処理系なら同じ結果が得られるよ。
tの中の状態に依存してるから、他で必ず同じ結果になるとは限らないと思うけど。
0112デフォルトの名無しさん2010/10/12(火) 20:15:22
アドレスじゃなくiの値そのものがスタックに積まれた
0113デフォルトの名無しさん2010/10/12(火) 20:22:19
>>111
ありがとうございます。
ご提示のコードでも確かに同様の結果が得られました。

>>112
ありがとうございます。
ということは、違う環境で例えばメンバ変数のスタックへの積まれ方が異なる場合には
違う値になってしまいますね。


仕事で携わってるものにこのようなコードがあり、
初めて見る書き方でしたので最初は意味が分からず
>>106のような検証コードを書いて、ようやく理解出来ました・・・。

正しくない使い方のようですのでgetInt()のようなゲッターを作って
取得するようにしようと思います。

ありがとうございました。
0114デフォルトの名無しさん2010/10/12(火) 20:25:41
そりゃiの値も積まれてるだろうけどそれじゃiだけ積んでるみたいじゃないか
0115デフォルトの名無しさん2010/10/12(火) 20:26:01
次は仮想関数を追加するんだ
0116デフォルトの名無しさん2010/10/12(火) 20:29:08
メンバ変数の定義を
private:
  int i;
  char c;
から
private:
  char c;
  int i;
と入れ替えて、

printf("t = %c\n", t);
とすると、「T」が表示されましたので、
クラスTestのインスタンスとして確保されたメモリ領域に
メンバ変数の定義順に配置されたって感じなんでしょうかねぇ。。。
0117デフォルトの名無しさん2010/10/12(火) 21:05:13
構造体について勉強すればわかるようになるよ
クラスも構造体も基本は一緒だから

でも>>106は未定義
0118デフォルトの名無しさん2010/10/13(水) 00:56:49
こんばんは。
参照型変数の寿命に関連してお伺いします。
紙面の都合上かなり省いていますが、下記コードでのretの使い方は正しいでしょうか?
(分かりづらいようでしたら、どこかに張ります)

まず、foo()は変更できない関数です。
処理としては、クラスXXXのメンバ変数のconst参照を返しています。
この参照をそのまま取得したいのですが、cがNULLの時はfoo()を呼べないので、
ifブロック外のポインタretに代入するようにしました。
動くことは動くのですが、ifブロックを抜ける時にRetが消えるような
気がしてなりません。よろしくお願いします。

XXX *c = yyy.GetPointer();
const vector<int> *ret = NULL;
if (c != NULL) {
 const vector<int>& Ret = c->foo();
 ret = &Ret;
}
 :
if (c != NULL) {
std::for_each(ret->begin(), ret->end(), print);
}
0119デフォルトの名無しさん2010/10/13(水) 01:06:22
追記です。
この(元のコードの)目的は、
(fooが取得できれば、)fooの返り値に対して最後のfor_eachを行うことです。

制限ばかりで申し訳ないですが、他の関係の無い処理が入る都合上、
for_eachの部分を上のfooの部分と同じブロックに入れることができません。
0120デフォルトの名無しさん2010/10/13(水) 01:10:09
>>118
>ifブロックを抜ける時にRetが消えるような
>気がしてなりません。よろしくお願いします。

消えるよ
当たり前だろ
ブロック内しか寿命がない

>動くことは動くのですが、

たまたま動いているだけ
Retはブロックの外で定義しないと
その場合参照型にはできないね
0121デフォルトの名無しさん2010/10/13(水) 01:11:59
何度もすみません。誤解の生じる表現があったので訂正します。
× 他の関係の無い処理が入る都合上、
○ 既存のコードの制御フローを変更できない都合上、
0122デフォルトの名無しさん2010/10/13(水) 01:15:39
知らねーよ
バグってはっきりわかったんだから修正するのが当たり前だろ
0123デフォルトの名無しさん2010/10/13(水) 01:22:58
>>118
Retを介す必要なくね?

ret = c->foo();
0124デフォルトの名無しさん2010/10/13(水) 01:40:25
>>123
なるほど。>>118を再掲しますと
> 処理としては、クラスXXXのメンバ変数のconst参照を返しています。
なので
ret = &(c->foo())
となるかと思いますがretの指すアドレスは、
「ifブロック内の一時的な変数」ではなくて「cのメンバ変数」のアドレスである。
という理解でよいのでしょうか?

加えて、retの有効範囲はcが有効である間という認識でよいのでしょうか?
0125デフォルトの名無しさん2010/10/13(水) 01:42:53
こんな感じじゃだめなん?

class C {
int i;
public:
C(int j) : i(j) {}
void foo() const {
std::cout << i << ' ';
}
};

int main()
{
const std::vector<C> *ret = 0;
std::vector<C> vi;

for (int i = 0; i < 10; i++)
vi.push_back(C(i));

ret = &vi;

std::for_each(ret->begin(), ret->end(), std::mem_fun_ref(&C::foo));
}
0126デフォルトの名無しさん2010/10/13(水) 02:11:29
>>124
それで動くはず。
foo() が const 参照を返すのなら、参照先は c のメンバ変数そのものだから、
&演算子でメンバ変数そのもののアドレスがとれる。

もっとも、その程度の処理なら、これで十分だけどね。
std::for_each(c->foo()->begin(), c->foo()->end(), print);
0127デフォルトの名無しさん2010/10/13(水) 02:41:58
これが一番簡単だったりする

class C : public std::unary_function<int, void> {
int i;
public:
void operator()(int i) const {
std::cout << i << ' ';
}
};

int main()
{
const std::vector<int> *ret;
std::vector<int> vi;

for (int i = 0; i < 10; i++)
vi.push_back(i);

ret = &vi;

std::for_each(ret->begin(), ret->end(), C());
}
0128デフォルトの名無しさん2010/10/13(水) 13:46:42
DLLが投げた例外をEXEでキャッチするなんてことしていいんですか?
0129デフォルトの名無しさん2010/10/13(水) 14:01:12
>>128
コンパイラのマニュアルを見ろ。
いちおう、同じコンパイラ+同じ設定でコンパイルしてるなら問題ない可能性が高いとは言える。
0130デフォルトの名無しさん2010/10/13(水) 14:03:32
DLLはCで書いてC++でラップするのが安全でよい
0131デフォルトの名無しさん2010/10/13(水) 14:14:30
ラップするときは catch (...) を忘れずにな。
0132デフォルトの名無しさん2010/10/13(水) 18:49:54
>>125-127
お返事が遅れました。
確かに、c->foo()->begin()で十分ですね。コレがよさそうです。

あと知らなかったのでmem_fun_ref調べてみましたが、
オブジェクトを作らなくても関数を呼べるのは面白いですね。

ありがとうございました。
0133デフォルトの名無しさん2010/10/13(水) 23:08:36
std::から始まる関数は、stlのなんですか?
0134デフォルトの名無しさん2010/10/13(水) 23:24:43
C++の標準ライブラリはstd名前空間にあるんだよ
0135デフォルトの名無しさん2010/10/14(木) 00:44:43
namespace foo{
namespace std{ void bar(); }
void baz() { std::bar(); }
}

まあこんなことするやつはいないと思いたい
0136デフォルトの名無しさん2010/10/14(木) 00:46:33
printf も本当は std::printf なんだぜ
0137デフォルトの名無しさん2010/10/14(木) 01:37:54
でも std:: 付けなくても使えるよね
0138デフォルトの名無しさん2010/10/14(木) 01:41:55
>>137
それは黒歴史。後方互換性とも言う。
0139デフォルトの名無しさん2010/10/14(木) 01:50:34
でもstdにあるものと同名のもの作る方がおかしいと思う
0140デフォルトの名無しさん2010/10/14(木) 02:10:29
>>139 find とか予約されたら死ねる。
0141デフォルトの名無しさん2010/10/14(木) 07:42:09
おっぱいを型にはめようとする人たち
http://togetter.com/li/59043

綾瀬はるかのおっぱいはどの型で宣言すればいいですか?
0142デフォルトの名無しさん2010/10/14(木) 08:16:24
>>141
int
0143デフォルトの名無しさん2010/10/14(木) 13:00:47
std::pairかな。
0144デフォルトの名無しさん2010/10/14(木) 13:38:43
std::pair<float,float>
0145デフォルトの名無しさん2010/10/14(木) 13:47:40
ある関数Aから関数Bを呼び出したとします。
関数Bでは関数Cを呼び、関数Cは関数Dを呼び・・・と何層にもなっているとします。
ここで、関数Cや関数Dから、goto文のように直接関数Aにreturnすることはできるでしょうか?
0146デフォルトの名無しさん2010/10/14(木) 13:49:05
throw
0147デフォルトの名無しさん2010/10/14(木) 13:57:36
>>145
エラー処理なら throw 〜 catch で。
それ以外ならもう少し詳しく状況を。できればコードで。
0148デフォルトの名無しさん2010/10/14(木) 13:58:55
もしかして setjmp/longjmp の出番なのか?
0149デフォルトの名無しさん2010/10/14(木) 14:10:16
pair<jmp_buf,jmp_buf>
0150デフォルトの名無しさん2010/10/14(木) 14:16:30
コンパイラを作っていて、入力コードにある一定数のエラーが出たり、致命的なエラーが出たときに処理を戻すようにしたいのです。
try〜catchは少し調べてみましたが、例外がおきたときに特定の処理をするようなので、処理を関数Aに戻すのは難しいのでは・・・と思います。
setjmp/longjmpはぴったりあってるような気がします。
ただ、goto文と同じくあまり推奨されてないのが不安ですが・・・
0151デフォルトの名無しさん2010/10/14(木) 14:40:55
setjmpは、C++ではスタック上のオブジェクトのデコンストラクタが呼ばれないので、
使用してはいけない。throwが正解。
■ このスレッドは過去ログ倉庫に格納されています