gpt4 book ai didi

c++ - 从 boost::shared_ptr 返回 C 字符串

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:21:56 29 4
gpt4 key购买 nike

我将一些 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 %s\n", stringValue);

到目前为止它有效,如printf在标准输出上输出正确的值。但是,使用 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)

编辑:评论中的问题是 what is the desired effect? .我最初的目标是在不分配任何额外内存的情况下将字符串返回给 C 调用者,但通常的方法似乎是在内存中分配另一个字符串并返回它或 NULL给来电者。

编辑 2:我想避免不必要的内存分配 的原因基本上是因为我记得 Ayende 的一篇文章 https://ayende.com/blog/161281/robs-sprint-the-cost-of-getting-data-from-leveldb关于在可以通过 C/C# 绑定(bind)从 leveldb 获取字符串之前发生了多少复制。

我想避免同样的陷阱,但我认为只有尽量减少额外的内存分配才有可能。

最佳答案

在考虑了我真正想要实现的目标(简单而安全的 C-API)之后,我决定将一个新分配的字符串返回给客户端。最终解决方案(目前)如下所示:

extern "C" int Hazelcast_Map_get_int_string(
Hazelcast_Client_t *hazelcastClient,
const char *mapName,
int key,
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, "int_string_map", 10, &stringValue, &err) != 0) {
printf("ERR Map get failed: %s\n", err);
Hazelcast_free(err); err = NULL;
} else {
printf("got value from map %s\n", stringValue);
free(stringValue);
}

我认为这很容易使用,同时还提供错误处理。

关于c++ - 从 boost::shared_ptr<string> 返回 C 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37062391/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com