从C++;功能 我有一个C++函数,它构造了 STD::String 。我希望它将这个字符串的Cconst char*返回给调用者。我正在使用c_str()来取出c字符串,但是可以在返回字符串后解除分配,因为生成的缓冲区属于std::string

从C++;功能 我有一个C++函数,它构造了 STD::String 。我希望它将这个字符串的Cconst char*返回给调用者。我正在使用c_str()来取出c字符串,但是可以在返回字符串后解除分配,因为生成的缓冲区属于std::string,c++,C++,我是否应该执行类似于返回strdup(str.c_str())的操作?那感觉不对 (我是C++初学者,请原谅我这个问题看起来很愚蠢)。 我应该像returnstrdup(str.c_str())这样做吗 是的,您应该,或者复制到调用者提供的缓冲区中。顺便说一句,在这种情况下,您需要返回char*而不是const char*,因为调用者必须能够释放字符串 那感觉不对 我知道这种感觉,但这是一条路要走。C++与C兼容,但它们之间的边界没有摩擦。 在一个库中分配内存并将其释放到另一个库中不是一个好主意

我是否应该执行类似于返回strdup(str.c_str())的操作?那感觉不对

<>(我是C++初学者,请原谅我这个问题看起来很愚蠢)。 我应该像return
strdup(str.c_str())
这样做吗

是的,您应该,或者复制到调用者提供的缓冲区中。顺便说一句,在这种情况下,您需要返回
char*
而不是
const char*
,因为调用者必须能够
释放字符串

那感觉不对


我知道这种感觉,但这是一条路要走。C++与C兼容,但它们之间的边界没有摩擦。

在一个库中分配内存并将其释放到另一个库中不是一个好主意。 如果预先知道缓冲区的大小,可以考虑将已分配的缓冲区传递给函数,然后只写入该缓冲区

如果事先不知道大小,考虑将回调函数传递给函数,它接收<代码> const char */COD>作为参数:

typedef void (*ResultCallback)( void* context, const char* result );

void Foo( ResultCallback resultCallback, void* context )
{
     std::string s = "....";
     resultCallback( context, s.c_str() );
}
ResultCallback
的实现可以分配所需的内存并复制
result
指向的缓冲区。我假设C,所以我没有显式地向void*
转换

void UserCallback( void* context, const char* result )
{
    char** copied = context;
    *copied = malloc( strlen(result)+1 );
    strcpy( *copied, result );
}

void User()
{
    char* result = NULL;

    Foo( UserCallback, &result );

    // Use result...
    if( result != NULL )
        printf("%s", result);

    free( result );
}

这是最具可移植性的解决方案,甚至可以处理无法提前知道返回字符串大小的最困难情况。

std::string::c_str
返回的指针仅在相应的
std::string
对象处于活动状态时才有效。因此,无法从函数返回该指针。这没什么错。如果你想要一份拷贝,你必须提供你自己的内存,并在上面拷贝数据

要做到这一点,您可以使用几种不同的方法

好的用户关心所有权,并使用难以滥用的接口


版本1(原语):

char* foo() {
    std::string a = "blah";
    return strdup(a.c_str());
}
struct free_delete { void operator()(void* x) { free(x); } };
template<typename T> using unique_c_ptr = std::unique_ptr<T,free_delete>;

unique_c_ptr<char[]> foo() {
    std::string a = "blah";
    return unique_c_ptr<char[]>(strdup(a.c_str()));
}

auto p = foo();
char* cp = p.get(); // gets raw pointer
void foo(char* buffer, size_t size) {
     std::string a = "blah";
     strncpy(buffer, a.c_str(), size);
}

char buffer[128];
foo(buffer, 128);
这看起来很简单,但是谁会在意删除由strdup分配的内存呢?函数的用户很可能忘记调用
free


第2版(C++11):

char* foo() {
    std::string a = "blah";
    return strdup(a.c_str());
}
struct free_delete { void operator()(void* x) { free(x); } };
template<typename T> using unique_c_ptr = std::unique_ptr<T,free_delete>;

unique_c_ptr<char[]> foo() {
    std::string a = "blah";
    return unique_c_ptr<char[]>(strdup(a.c_str()));
}

auto p = foo();
char* cp = p.get(); // gets raw pointer
void foo(char* buffer, size_t size) {
     std::string a = "blah";
     strncpy(buffer, a.c_str(), size);
}

char buffer[128];
foo(buffer, 128);

在此版本中,调用方显式地负责管理内存。他可以把结果存储在任何他喜欢的地方。它的缺点是,用户必须猜测一个好的缓冲区大小…

为什么返回
const char*
类型?这是在一个库中,它将与直接的C链接。C字符串是一个指针。这需要有目的地加以解构。如果
std::string
保存了字符串,并且如果它被破坏了,它也破坏了C字符串,那么我就没有任何意义了。即使在原始的
std::String
对象被销毁后,C字符串仍应存在。在
std::String
被销毁后,指针仍然存在,这是完全无用的。它指向的内存被释放了,所以你不能真正地使用它做任何事情——除非你按照OP的建议正确地复制它。如果你需要一个C风格的字符串,这就是方法@OP:只需知道调用方拥有这个返回值,并且负责<代码>免费> /Cux> ING。<代码> StrudU/S>是不是标准的C++函数。它是Posix的一部分。@Snps:“类似于
strdup
”。此外,OP可能针对POSIX平台;有POSIX函数是有原因的。@larsmans是的,我只是觉得值得一提。