注:ネタなので役にはたちません
なぜか VC++ でこんなコードが上手く動きました。
# include <stdio.h>
# include <atlstr.h>
int main()
{
ATL::CString str("hogehoge");
// なぜか動く
printf("%s\n", str);
// 普通はこう
printf("%s\n", (LPCSTR)str);
// もしくはこう?
printf("%s\n", str.GetString());
return 0;
}
もちろん std::string
で似たようなことしてもまともに動きません。
# include <stdio.h>
# include <string>
int main()
{
std::string str("hogehoge");
// まともに動かない
printf("%s\n", str);
// こうしなければならない
printf("%s\n", str.c_str());
return 0;
}
ATL::CString
と似たような方法で printf
などの可変個引数にそのまま渡してもうまく動いているような気がしてしまう文字列クラスを作ってみました。
ただし gcc では実行出来なかったし、VC++ でも動作は保証されません( http://msdn.microsoft.com/ja-jp/library/vstudio/awkwbzyc.aspx )。
# include <stdio.h>
# include <string.h>
# include <crtdbg.h>
class ore_string
{
private:
char* _str;
struct data_t
{
size_t len;
int ref;
};
char* buffer() const
{
return _str - sizeof(data_t);
}
data_t* data() const
{
return reinterpret_cast<data_t*>(buffer());
}
public:
ore_string(const char* str)
{
size_t len = strlen(str);
_str = new char[len + 1 + sizeof(data_t)] + sizeof(data_t);
data()->len = len;
data()->ref = 1;
strcpy_s(_str, len + 1, str);
}
ore_string(const ore_string& rhs)
{
_str = rhs._str;
data()->ref++;
}
~ore_string()
{
if(--data()->ref == 0)
{
delete[] buffer();
}
}
const char* c_str() const
{
return _str;
}
int length() const
{
return data()->len;
}
int refcount() const
{
return data()->ref;
}
};
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
ore_string str1("hogehoge");
printf("%s pointer:%p length:%d refcount:%d\n", str1, str1.c_str(), str1.length(), str1.refcount());
{
ore_string str2(str1);
printf("%s pointer:%p length:%d refcount:%d\n", str1, str1.c_str(), str1.length(), str1.refcount());
printf("%s pointer:%p length:%d refcount:%d\n", str2, str2.c_str(), str2.length(), str2.refcount());
}
printf("%s pointer:%p length:%d refcount:%d\n", str1, str1.c_str(), str1.length(), str1.refcount());
printf("sizeof ore_string=%lu char*=%lu\n", sizeof(str1), sizeof(char*));
return 0;
}
実行結果
hogehoge pointer:00586C50 length:8 refcount:1
hogehoge pointer:00586C50 length:8 refcount:2
hogehoge pointer:00586C50 length:8 refcount:2
hogehoge pointer:00586C50 length:8 refcount:1
sizeof ore_string=4 char*=4
ポイントは、文字長や参照カウンタを持っているにも関わらす sizeof(str1)
と sizeof(char*)
が同じであることです。
「文字長+参照カウンタ+文字列」分のバッファを確保して、バッファのアドレスを「文字長+参照カウンタ」だけズラして ore_string
の唯一のメンバ変数にしています。