ページ 1 / 1
string型とchar型について
Posted: 2014年12月23日(火) 13:47
by kouki
文字列についてよく理解できてないので、string型をchar型のポインタで返す関数を作ってみました。
しかし、何回か呼ぶと最後に呼んだ時の変数で初期化されてしまいます。
これを何とか回避したいのですが、方法などはあるのでしょうか。
コード:
const char* test( const string& str )
{
return str.c_str();
}
const char* str1 = test( "1234" );
const char* str2 = test( "5678" );
〜ここでログ出力〜
ログ
str1 = 5678
str2 = 5678
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:21
by みけCAT
引数のデータのコピーを取るといいかもしれません。
► スポイラーを表示
コード:
#include <cstdio>
#include <string>
#include <vector>
using std::string;
const char* test( const string& str )
{
static std::vector<string> str_list;
str_list.push_back( str );
return str_list.back().c_str();
}
int main( void )
{
const char* str1 = test( "1234" );
const char* str2 = test( "5678" );
printf( "str1 = %s\n" , str1 );
printf( "str2 = %s\n" , str2 );
return 0;
}
【訂正】std::vectorの再確保後もc_str()が同じになるか自信が無いので、このコードだとダメかもしれません。
下に書き直します。
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:31
by Blue
みけCAT さんが書きました:
const char* test( const string& str )
{
static std::vector<string> str_list;
str_list.push_back( str );
return str_list.back().c_str();
}
[/code]
vectorだとキャパシティを超えたときに問題が出そうですね。listのほうがよさそう。
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:37
by みけCAT
コンストラクタとデストラクタを通るときに情報を出力するようにすると、
何が起きているかわかりやすくなるかもしれません。
コード:
#include <cstdio>
#include <string>
#include <vector>
using std::string;
struct hoge : public string {
hoge(): string() {
printf( "hoge %p constructer\n" , (void*)this );
}
hoge( const char* s ): string( s ) {
printf( "hoge %p constructer content=%s (%p)\n" , (void*)this , s , (void*)s );
}
hoge( const hoge& h ): string( h ) {
printf( "hoge %p constructer copy from %p\n" , (void*)this , (void*)&h );
}
~hoge() {
printf( "hoge %p destructer\n" , (void*)this );
}
hoge& operator=( const hoge& h ) {
printf( "hoge %p set hoge %p\n" , (void*)this , (void*)&h );
*((string*)this) = h;
return *this;
}
hoge& operator=( const char* s ) {
printf( "hoge %p set content %s (%p)\n" , (void*)this , s , (void*)s );
*((string*)this) = s;
return *this;
}
const char* c_str() const {
const char* ret = ((string*)this)->c_str();
printf( "hoge %p c_str() = %p\n" , (void*)this , (void*)ret );
return ret;
}
};
const char* test( const hoge& str )
{
return str.c_str();
}
int main( void )
{
const char* str1 = test( "1234" );
const char* str2 = test( "5678" );
printf( "str1 = %s (%p)\n" , str1 , (void*)str1 );
printf( "str2 = %s (%p)\n" , str2 , (void*)str2 );
return 0;
}
【修正】std::vectorを用いたtest関数(No: 2と同じ)を削除
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:46
by kouki
皆様ありがとうございます!
何回もと書いてしまったのですが、2回以降からこの現象が発生しております。
値は呼び出し先の関数内で保持できれば十分なのですが、よくやり方がわからなくて・・・。
vectorなどを使う方法しかないのでしょうか?
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:48
by kouki
何度もすみません!
ログを出すと、test関数内では正しい値を保持しております。
これを戻り値で返すと、最後に呼んだものに上書きされてしまいます。
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:49
by みけCAT
vectorは使うべきではないです。訂正版のコードです。
コード:
#include <cstdio>
#include <string>
using std::string;
const char* test( const string& str )
{
class str_list_node {
private:
string data;
str_list_node* next;
public:
const char* get_str() const
{
return data.c_str();
}
void set_next ( str_list_node* next_node )
{
next = next_node;
}
str_list_node(): data(), next( NULL )
{
}
str_list_node( const string& str): data ( str ), next( NULL )
{
}
~str_list_node()
{
if ( next != NULL ) delete next;
}
};
static str_list_node head;
static str_list_node* next_to_write = &head;
str_list_node* next_node = new str_list_node( str );
next_to_write->set_next ( next_node );
next_to_write = next_node;
return next_node->get_str();
}
int main( void )
{
const char* str1 = test( "1234" );
const char* str2 = test( "5678" );
printf( "str1 = %s\n" , str1 );
printf( "str2 = %s\n" , str2 );
return 0;
}
ログ出力をつけるとこうなります。
► スポイラーを表示
コード:
#include <cstdio>
#include <string>
#include <vector>
struct hoge : public std::string {
hoge(): std::string() {
printf( "hoge %p constructer\n" , (void*)this );
}
hoge( const char* s ): std::string( s ) {
printf( "hoge %p constructer content=%s (%p)\n" , (void*)this , s , (void*)s );
}
hoge( const hoge& h ): std::string( h ) {
printf( "hoge %p constructer copy from %p\n" , (void*)this , (void*)&h );
}
~hoge() {
printf( "hoge %p destructer\n" , (void*)this );
}
hoge& operator=( const hoge& h ) {
printf( "hoge %p set hoge %p\n" , (void*)this , (void*)&h );
*((std::string*)this) = h;
return *this;
}
hoge& operator=( const char* s ) {
printf( "hoge %p set content %s (%p)\n" , (void*)this , s , (void*)s );
*((std::string*)this) = s;
return *this;
}
const char* c_str() const {
const char* ret = ((std::string*)this)->c_str();
printf( "hoge %p c_str() = %p\n" , (void*)this , (void*)ret );
return ret;
}
};
typedef hoge string;
const char* test( const string& str )
{
class str_list_node {
private:
string data;
str_list_node* next;
public:
const char* get_str() const
{
return data.c_str();
}
void set_next ( str_list_node* next_node )
{
next = next_node;
}
str_list_node(): data(), next( NULL )
{
}
str_list_node( const string& str): data ( str ), next( NULL )
{
}
~str_list_node()
{
if ( next != NULL ) delete next;
}
};
static str_list_node head;
static str_list_node* next_to_write = &head;
str_list_node* next_node = new str_list_node( str );
next_to_write->set_next ( next_node );
next_to_write = next_node;
return next_node->get_str();
}
int main( void )
{
const char* str1 = test( "1234" );
const char* str2 = test( "5678" );
printf( "str1 = %s (%p)\n" , str1 , (void*)str1 );
printf( "str2 = %s (%p)\n" , str2 , (void*)str2 );
return 0;
}
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:55
by Blue
kouki さんが書きました:何度もすみません!
ログを出すと、test関数内では正しい値を保持しております。
これを戻り値で返すと、最後に呼んだものに上書きされてしまいます。
test関数の戻り値は一時オブジェクトであるstd::stringの値を返しているので想定した通りになりません。
イメージ的には
コード:
const char* str1;
const char* str2;
{
std::string str("1234");
str1 = str1.c_str();
}
{
std::string str("5678");
str2 = str2.c_str();
}
と同じ様なことです。
寿命が尽きているオブジェクトの値を使うこと自体が間違いです。
(たまたまstr2は正しく出ているだけ)
Re: string型とchar型について
Posted: 2014年12月23日(火) 14:56
by みけCAT
kouki さんが書きました:string型をchar型のポインタで返す関数を作ってみました。
そもそも「string型をchar型のポインタで返す」という操作の定義がよくわからないのですが、
「string型」(そもそもC++のSTLのstd::string型(std::basic_string<char>型)である保証も無い)
のインスタンスのc_str()の戻り値を返せばいいのですね?
kouki さんが書きました:値は呼び出し先の関数内で保持できれば十分なのですが、よくやり方がわからなくて・・・。
vectorなどを使う方法しかないのでしょうか?
「値」とは何ですか?
const char*型の「値」を保持できれば、それが指す先の内容は保証しなくていいのですか?
それとも、返ってきたポインタが指すデータを保持したいのですか?
Re: string型とchar型について
Posted: 2014年12月24日(水) 10:52
by kouki
サンプルソースまでありがとうございます!
頂いた関数だと問題なく正しい値を取得出来ました。
私の関数の戻り値のやり方はまずかったのですね。
やりたかったのは
string型のc_str()でchar型に変換する部分を関数でということになります。
思いついてやってみたのですが、上手くいかなかったので、
何か書き方が違うんだろうなと思い質問させて頂きました。
文字列についてよく理解できていなくて・・・。
やりたかったことは頂いた関数と同じことなのですが、
あまりにも複雑で理解出来ませんでした。
理解できるように解読させて下さい!
本当にありがとうございました!!!