加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 从boost :: shared_ptr返回C字符串

发布时间:2020-12-16 06:51:50 所属栏目:百科 来源:网络整理
导读:我在函数中包含一些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*
我在函数中包含一些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);
}

我认为这很容易使用,同时仍然提供错误处理.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读