私はC.はブーストからC文字列を返す:: shared_ptrの<string>
で利用可能なC++のメソッドC++ APIメソッドは、通常boost::shared_ptr<T>
オブジェクトを返すをするために機能におけるいくつかのC++のコードをラップしています。 C++での私のエクスポート機能は、次のようになります。
extern "C" const char *Hazelcast_Map_get_int_string(
Hazelcast_Client_t *hazelcastClient,
const char *mapName,
int key,
char** errptr
) {
IMap<int, string> map = hazelcastClient->client->getMap<int, string>(mapName);
boost::shared_ptr<string> value = map.get(key);
string *strValue = value.get();
return strValue->c_str();
}
私のCクライアントコードは次のようになります。printf
は標準出力に正しい値を出力として
const char *stringValue = NULL;
stringValue = Hazelcast_Map_get_int_string(client, "int_string_map", 10, &err);
printf("got value from map %s\n", stringValue);
それは、これまでに動作します。ただし、コードをvalgrind
でチェックすると、無効な読み取りエラーが表示されます。だから私はポインタを渡すと何か間違っていると思うが、私は本当に何が問題なのか理解できない。
strdup
の値をboost::shared_ptr<string>
にすることができますか、それとも私は何をする必要がありますか?
ここvalgrind
エラー:
==20635== Invalid read of size 1
==20635== at 0x10034C6BF: strlen (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==20635== by 0x1006136E7: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==20635== by 0x10063C35C: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==20635== by 0x10061201D: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==20635== by 0x10060FEB7: printf (in /usr/lib/system/libsystem_c.dylib)
==20635== by 0x100001E6A: main (in ./hazelcastCClientTest)
==20635== Address 0x100de9c41 is 1 bytes inside a block of size 24 free'd
==20635== at 0x10034B2F7: free (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==20635== by 0x1000068BF: void boost::checked_delete<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) (in ./hazelcastCClientTest)
==20635== by 0x100006888: boost::detail::sp_counted_impl_p<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::dispose() (in ./hazelcastCClientTest)
==20635== by 0x1000054AD: boost::detail::sp_counted_base::release() (in ./hazelcastCClientTest)
==20635== by 0x100005449: boost::detail::shared_count::~shared_count() (in ./hazelcastCClientTest)
==20635== by 0x100005414: boost::detail::shared_count::~shared_count() (in ./hazelcastCClientTest)
==20635== by 0x1000053F8: boost::shared_ptr<int>::~shared_ptr() (in ./hazelcastCClientTest)
==20635== by 0x100004054: boost::shared_ptr<int>::~shared_ptr() (in ./hazelcastCClientTest)
==20635== by 0x10000347F: Hazelcast_Map_get_int_string (in ./hazelcastCClientTest)
==20635== by 0x100001E54: main (in ./hazelcastCClientTest)
==20635== Block was alloc'd at
==20635== at 0x10034AEBB: malloc (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==20635== by 0x10038E7DD: operator new(unsigned long) (in /usr/lib/libc++.1.dylib)
==20635== by 0x1000B8C80: hazelcast::client::serialization::pimpl::DataInput::readUTF() (DataInput.cpp:147)
==20635== by 0x1000E367F: std::__1::auto_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > hazelcast::client::serialization::pimpl::SerializationService::toObject<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(hazelcast::client::serialization::pimpl::Data const&) (SerializationService.cpp:590)
==20635== by 0x10000659D: std::__1::auto_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > hazelcast::client::proxy::ProxyImpl::toObject<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(hazelcast::client::serialization::pimpl::Data const&) (in ./hazelcastCClientTest)
==20635== by 0x100006413: std::__1::auto_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > hazelcast::client::proxy::ProxyImpl::toObject<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::auto_ptr<hazelcast::client::serialization::pimpl::Data>) (in ./hazelcastCClientTest)
==20635== by 0x10000484B: hazelcast::client::IMap<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::get(int const&) (in ./hazelcastCClientTest)
==20635== by 0x10000338F: Hazelcast_Map_get_int_string (in ./hazelcastCClientTest)
==20635== by 0x100001E54: main (in ./hazelcastCClientTest)
EDIT:コメントからの質問がwhat is the desired effect?
ました。私の最初の目標は、追加のメモリ割り当てをせずにCの呼び出し元に文字列を返すことでしたが、メモリに別の文字列を割り当てて呼び出し元にNULL
を返すのが通常のようです。
EDIT 2:私は1つは、C/C#バインディングを通じてleveldbから文字列を取得できるようになるまで起こるどのくらいのコピーについてAyende https://ayende.com/blog/161281/robs-sprint-the-cost-of-getting-data-from-leveldbから記事を思い出したので、私は回避不要なメモリ割り当てしたい理由は、基本的でした。
私は同じ落とし穴を避けたいと思いましたが、追加のメモリ割り当てを最小限に抑えることしかできないと思います。
どのような効果がありますか?あなたは呼び出し元にメモリを解放しますか?それとも、別のやり方で動かしたいですか?呼び出し側が文字列を 'free'したい場合は、' strdup'が最適な解決法です。ポインタをこの関数の次の呼び出しに有効にしたい場合は、おそらく 'shared_ptr'静的にしてください。呼び出し元にバッファーと最大長を渡したいのでしょうか? –
@DavidSchwartzは良い質問ですが、不要なメモリ使用を避けるために自分でメモリを割り当てる必要はありませんが、使いやすいAPIが必要です。 leveldbがhttps://github.com/emnl/leveldb-c-example/blob/master/leveldb_example.cをどのようにしているかを調べようとしましたが、呼び出し元がメモリを解放する責任を負いません。これは私が達成したかったようです。 – Max
leveldb_getは、mallocで作成され、memcpyで埋められた文字列へのポインタを返します。それはいつか解放されなければならない - 私は発信者がそれをするつもりだと思う。ヘッダーファイルによると、 '/ *見つからなければNULLを返します。 malloc()はそれ以外の場合は配列を返します。 配列の長さをvallenに格納します。 */ にextern char型のleveldb_get( leveldb_tの*デシベル、 のconst leveldb_readoptions_t *オプション、 のconstのchar *キー、size_tのKEYLEN、 size_tの* vallen、 のchar ** errptr);私はそれがこのように行って見てきた ' –