c – 从boost :: shared_ptr返回C字符串
我在函数中包含一些C代码,以便在C中使C方法可用.
C API方法返回boost :: shared_ptr< T>对象通常.我在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客户端代码如下所示: const char *stringValue = NULL; stringValue = Hazelcast_Map_get_int_string(client,"int_string_map",10,&err); printf("got value from map %sn",stringValue); 它工作到目前为止,因为printf在stdout上输出正确的值.但是,使用valgrind检查代码时,它显示无效的读取错误.因此,我认为我在传递指针方面做错了,但我无法真正理解问题是什么. 我是否可以避免必须限制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::allocator<char> >*) (in ./hazelcastCClientTest) ==20635== by 0x100006888: boost::detail::sp_counted_impl_p<std::__1::basic_string<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::allocator<char> > > hazelcast::client::serialization::pimpl::SerializationService::toObject<std::__1::basic_string<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::allocator<char> > > hazelcast::client::proxy::ProxyImpl::toObject<std::__1::basic_string<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::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::allocator<char> > >::get(int const&) (in ./hazelcastCClientTest) ==20635== by 0x10000338F: Hazelcast_Map_get_int_string (in ./hazelcastCClientTest) ==20635== by 0x100001E54: main (in ./hazelcastCClientTest) 编辑:评论中的问题是什么是期望的效果?我最初的目标是将字符串返回给C调用者而不需要任何额外的内存分配,但似乎通常的方法是在内存中分配另一个字符串并将该值或NULL返回给调用者. 编辑2:我想避免不必要的内存分配的原因基本上是因为我记得Ayende https://ayende.com/blog/161281/robs-sprint-the-cost-of-getting-data-from-leveldb的一篇文章,关于复制会发生多少,直到可以通过C/C++#绑定从leveldb获取字符串. 我想避免同样的陷阱,但我认为只有最小化额外的内存分配才有可能. 解决方法
在考虑了我实际想要实现的目标(简单而安全的C-API)后,我决定将新分配的字符串返回给客户端.最终的解决方案(现在)看起来像这样:
extern "C" int Hazelcast_Map_get_int_string( Hazelcast_Client_t *hazelcastClient,char **value,char** errptr ) { assert(hazelcastClient != NULL); assert(hazelcastClient->client != NULL); assert(mapName != NULL); assert(value != NULL); try { auto map = hazelcastClient->client->getMap<int,string>(mapName); boost::shared_ptr<string> sharedPtr = map.get(key); string *ptr = sharedPtr.get(); if (ptr == NULL) { return 0; } *value = strdup(ptr->c_str()); return 0; } catch(const std::runtime_error& re) { saveMessageInErrPtr(errptr,re.what()); } catch(const std::exception& ex) { saveMessageInErrPtr(errptr,ex.what()); } catch(...) { saveUnknownErrorOccurredMessageInErrPtr(errptr); } return 1; } 除了在errptr中提供错误消息之外,我还决定使用函数的返回值来指示成功/失败状态. 客户端代码如下所示: char *stringValue = NULL; if (Hazelcast_Map_get_int_string(client,&stringValue,&err) != 0) { printf("ERR Map get failed: %sn",err); Hazelcast_free(err); err = NULL; } else { printf("got value from map %sn",stringValue); free(stringValue); } 我认为这很容易使用,同时仍然提供错误处理. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |