- 追加された行はこの色です。
- 削除された行はこの色です。
#include(C++TipsMenu,notitle)
* 一時オブジェクトの寿命についての注意 [#t655d13c]
一時オブジェクトは、次の行にいくと寿命が尽きてそのオブジェクトへの参照は未定義になります。~
実装の具合や最適化オプション、コンパイラの種類によっては一見正常に動いてしまうので、注意が必要です。
#sh(cpp){{
#include <iostream>
using namespace std;
struct Hoge {
const char* char_ = nullptr;
Hoge(const char* c) : char_(c) {}
};
struct Piyo {
const Hoge* hoge_;
Piyo(const Hoge& hoge) : hoge_(&hoge) {
//cout << "Piyo(hoge)" << endl; // このコメントを活かすとなぜかうごく
}
};
int main() {
Piyo piyo = Piyo(Hoge("hogehoge"));
// 上のHogeの寿命は尽きているので、piyo.hoge_ は未定義な値になる?
// 何のエラーもなく動いてしまうのが怖い。
// Piyoのコンストラクタに実装を書くか、最適化を外すと期待通りに動いてしまう。
if (piyo.hoge_->char_ == nullptr) {
cout << "Error!" << endl;
}
else {
cout << piyo.hoge_->char_;
}
}
}}
http://melpon.org/wandbox/permlink/3x1ZGslfSFw7IGFG
* 指定した値で初期化するenumクラス [#t10b75af]
enumで定義した変数は、暗黙のコンストラクタが呼ばれるとゼロが設定されます。
enumで定義した変数は、暗黙のコンストラクタが呼ばれるとゼロが設定されます。~
特定の値(たとえば、-1など)で初期化したい場合に便利なenumのwrapperクラスを作ってみました。
#sh(cpp){{
#include <iostream>
#include <map>
using namespace std;
enum Hoges {
Invalid = -1,
Hoge = 0,
Fuga = 1,
Piyo = 2,
Hogera = 3,
PiyoPiyo = 4,
};
// このmapは、値の初期値はHogeになる
map <int, Hoges> hoges1;
// 初期値をテンプレートパラメータで指定するenumクラス
template <typename EnumType, EnumType InitialValue>
struct initialized_enum {
EnumType value_;
initialized_enum(EnumType v = InitialValue) : value_(v) {}
operator EnumType () const { return value_; }
};
// このmapは、初期値がInvalid(-1)になる
map <int, initialized_enum<Hoges, Invalid>> hoges2;
int main() {
// Hogesの初期値は、Invalidにしたいけど、Hogeになる
cout << hoges1[0] << endl;
// initialized_enumだと、初期値を入れてくれる
cout << hoges2[0] << endl;
}
}}
http://melpon.org/wandbox/permlink/DSQ21IThska1JTQk
* テンプレートクラスのクラス変数(staticなインスタンス)を宣言する方法 [#ld6270af]
通常のクラス変数は、cppなどで明示的に宣言しないとインスタンスが生成されませんが、~
テンプレートクラスの場合は、ヘッダファイルで宣言するだけでクラス変数のインスタンスが生成されます。
意外と知られていないですが、便利な機能です。
http://melpon.org/wandbox/permlink/kKGoK7YiFfmkJyyM
* VisualStudioで、文字リテラルをUTF-8にする [#aa50c61d]
VisualStudioでは、ソースファイルの文字形式にかかわらず、コンパイル時に文字列リテラルはすべてシフトJISに変換されてしまいます。
たとえば、printf("漢字")というプログラムで、ソースコードがUTF-8でも実行時にはシフトJISで表示されます。
コンパイル時の文字コード変換機能をOFFにするやり方はわかりませんが、強制的にUTF-8にするには、以下の方法で可能です。
#sh(cpp){{
#if defined(_MSC_VER)
// 文字リテラルをUTF-8として処理する
#pragma execution_character_set("utf-8")
#endif
}}
* boost regex の使い方メモ [#i7857ca0]
XMLの文字エスケープのサンプル
#sh(cpp){{
#include <iostream>
#include <string>
#include <boost/regex.hpp>
namespace {
using std::string;
using boost::regex;
using boost::regex_replace;
string escape(const string& src) {
regex reg("(<)|(>)|(&)|(\\\")|(')");
string fmt("(?1<)(?2>)(?3&)(?4")(?5')");
return regex_replace(src, reg, fmt, boost::match_default|boost::format_all);
}
string unescape(const string& src) {
regex reg("(<)|(>)|(&)|(")|(')");
string fmt("(?1<)(?2>)(?3&)(?4\\\")(?5')");
return regex_replace(src, reg, fmt, boost::match_default|boost::format_all);
}
}
int main()
{
using namespace std;
string src = "hoge<hoge> fuga<'fuga'> &>_<\" <o'o> < &\n";
string result = escape(src);
cout << src << result << unescape(result);
}
}}
output
hoge<hoge> fuga<'fuga'> &>_<" <o'o> < &
hoge<hoge> fuga<'fuga'> &>_<" <o'o> &lt; &amp;
hoge<hoge> fuga<'fuga'> &>_<" <o'o> < &
* 複数の引数を必要とするオブジェクトのemplace (C++11) [#r828da13]
便利で高速なemplaceですが、mapやunordered_mapのように、pair型として保持するコンテナの場合、emplaceするときに困った問題があります。
1つの値から生成できるkey, valueの場合は問題ないのですが、
#sh(cpp){{
map<int,int> hoge;
hoge.emplace(1,2); // OK
}}
生成に2つの値が必要なクラスを格納する場合、問題があります。
#sh(cpp){{
struct Point {
Point(int x, int y);
};
map<int, Point> hoge;
hoge.emplace(1,2,3); // コンパイルエラー
}}
この書式では、(1,2,3)から、pair<int(1), Point(2,3)> を推測してくれません。
こんな時は、"piecewise_construct"という呪文を使えば、pairを召喚できます。
#sh(cpp){{
#include <vector>
#include <map>
#include <iostream>
struct Point {
int x_;
int y_;
Point(int x,int y) : x_(x), y_(y) {}
};
int main(int ac, char* av[]) {
using namespace std;
// vectorなら問題 ない//
vector<Point> hoge;
hoge.emplace_back(1,2);
// mapの場合は、key,valueでOK!
map<string, int> intMap;
intMap.emplace("hoge", 1);
// valueのコンストラクタの引数が2個以上の場合は厄介!
map<string, Point> hogeMap;
// hogeMap.emplace("hoge", 1, 2); // compile error!
hogeMap.emplace(piecewise_construct // pairのコンストラクタを召喚する呪文!
, forward_as_tuple("hoge") // tuple型の生成。make_tupleだとコピーされるので、
, forward_as_tuple(1,2)); // forward_as_tupleを使う
}
}}
参考URL
- piecewise_constructについて
-- https://sites.google.com/site/cpprefjp/reference/utility/piecewise_construct
- forward_as_tupleについて
-- https://sites.google.com/site/cpprefjp/reference/tuple/tuple/forward_as_tuple
* 定数の定義と静的構造体テーブルを同時に作るマクロ [#s2f22c6c]
定数の定義をソースコード上で行う場合、定数の定義と値の定義を同時に行いたい場合があります。
通常はこのように書きます。
#sh(cpp){{
enum EnumHoge { hoge, fuga, piyo };
struct HogeHoge {
EnumHoge id;
float value;
const char* name;
} const table[] = {
{ hoge, 1.0f, "hoge" },
{ fuga, 2.0f, "fuga" },
{ piyo, 3.0f, "piyo" },
};
}}
enumの定義と構造体の定義が冗長で、名前の文字列の定義も冗長です。~
しかし、魂を悪魔(#define)に売り渡せば、一発で記述できます。
#sh(c){{
// ここで定数を定義する(冗長でない単一の記載で済ませる)
#define LIST \
DEF(hoge, 1.0f), \
DEF(fuga, 2.0f), \
DEF(piyo, 3.0f)
// enumの生成
#undef DEF
#define DEF(a, b) a
enum EnumHoge { LIST };
// 構造体の生成
#undef DEF
#define DEF(a, b) {a, b, #a}
struct HogeHoge {
EnumHoge id;
float value;
const char* name;
} const table[] = { LIST };
}}
使用例
#sh(cpp){{
#include <stdio.h>
int main(int ac, char*av []) {
for (size_t n = 0; n < sizeof(table)/sizeof(HogeHoge); ++n) {
printf("table[%d] = id:%d value:%f name='%s'\n", n, table[n].id, table[n].value, table[n].name);
}
}
}}
結果
table[0] = id:0 value:1.000000 name='hoge'
table[1] = id:1 value:2.000000 name='gufa'
table[2] = id:2 value:3.000000 name='piyo'
ideone: http://ideone.com/HEIsAa#view_edit_box
* コンテナに対して、pushとpush_backを自動判別して追加するUtility (C++11) [#zc07fe71]
#sh(cpp){{
// decltypeを使ってコンテナに要素を追加する
// push_back()を持っている場合
template <typename CT, typename VT>
inline auto push_to_container(CT& container, VT&& val, int=0) -> decltype(container.push_back(val))
{
return container.push_back(val);
}
// push()がある場合
template <typename CT, typename VT>
inline auto push_to_container(CT& container, VT&& val) -> decltype(container.push(val))
{
return container.push(val);
}
}}
使用例
#sh(c){{
std::vector<int> hoge;
std::priority_queue<int> fuga;
...
push_to_container(hoge, 1); // hoge.push_back(1)が呼ばれる
push_to_container(fuga, 1); // fuga.push(1)が呼ばれる
}}
参考にしたページ
[[メンバー関数の存在を確かめる方法>http://codelogy.org/archives/2012/07/%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E9%96%A2%E6%95%B0%E3%81%AE%E5%AD%98%E5%9C%A8%E3%82%92%E7%A2%BA%E3%81%8B%E3%82%81%E3%82%8B%E6%96%B9%E6%B3%95.html]]
* VC++でイテレーターを高速化する [#lc845c91]
VC++では、イテレーターの範囲チェックが行われており、安全な反面、若干遅いです。~
以下の定義を行うことで、範囲チェックを無効にできます。([[C++ポケットリファレンス>http://astore.amazon.co.jp/hgodai-22/detail/4774157155]]より引用)~
#define _SECURE_SCL 0
ちなみに、以下の設定で範囲チェックが有効になります。
#define _SECURE_SCL_1
#define _HAS_ITERATOR_DEBUGGING 1
* boost mpl map for_each覚え書き [#p7da01c4]
boost::mplのvectorやmapをfor_eachするサンプル。
mapのkeyだけ回すmap_keysのようなフィルタの例も作ってみました。
#sh(cpp){{
#include <iostream>
#include <vector>
#include <string>
#include <typeinfo>
#include <boost/mpl/list.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/key_type.hpp>
using namespace boost;
using namespace std;
struct Disp {
template <class Type>
void operator()(const Type&) const {
cout << typeid(Type).name() << endl;
}
template <typename K, typename V>
void operator()(const mpl::pair<K,V>&) const {
cout << typeid(K).name() << "," << typeid(V).name() << endl;
}
} disp;
int main()
{
typedef mpl::list<int, std::string, char, std::vector<int> > tl;
typedef mpl::map<mpl::pair<int,char>, mpl::pair<int,int>, mpl::pair<char, char> > t2;
cout << "mpl list test" << endl;
mpl::for_each<tl>(disp);
cout << "mpl map test" << endl;
mpl::for_each<t2>(disp);
cout << "mpl map key_type test" << endl;
mpl::for_each<t2, mpl::lambda<mpl::key_type<t2, mpl::_1> > >(disp);
cout << "finish" << endl;
return 0;
}
}}
cpp_akiraさんのページにあったサンプルにmapを足してみました。
http://ideone.com/rrk1ZY