将std::string转换为const char*,出现错误

3
#include <iostream>
#include <sstream>

template <typename T>
const char* numberToString(T number) {
    std::ostringstream ss;
    ss << number;
    return ss.c_str();
}

int main() {
    printf(numberToString(123));
    return 0;
}

我的错误:

1>d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(8): error C2039: 'c_str' : is not a member of 'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>'
1>          d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(26) : see reference to function template instantiation 'const char *numberToString<int>(T)' being compiled
1>          with
1>          [
1>              T=int
1>          ]

为什么这不起作用?


1
文档:http://en.cppreference.com/w/cpp/io/basic_ostringstream - vz_
2
你不能从临时字符串中获取 const char* (c_str())。一旦你从 numberToString 返回,你的 stringstream 将被销毁,它的底层 std::string 也将被销毁。当你调用 c_str() 时,它将返回一个指向仅在 std::string 生命周期内有效的内容的指针。我建议使用 std::string 进行操作,因为它是一个对象(而不是指针),需要时会被复制。 - André Puel
4
FYI,标准库提供了这个功能,无需编写函数。http://en.cppreference.com/w/cpp/string/basic_string/to_string - Praetorian
你读过文档了,对吧?... - user529758
4个回答

7

c_strstd::string 的成员,而不是 ostringstream。如果你想从流中获取一个 string,请使用 str()。然而,请注意,从该 string 返回一个 const char* 是错误的 - 在你使用 const char* 之前,string 将会超出其作用域。因此,请让您的函数返回一个 string(或者让它获取一个要写入的缓冲区):

template <typename T>
std::string numberToString(T number) {
    std::ostringstream ss;
    ss << number;
    return ss.str();
}

4

std::ostringstream 没有 c_str() 函数。你想用的应该是:

template <typename T>
const char* numberToString(T number) 
{
    std::ostringstream ss;
    ss << number;
    return ss.str().c_str();
}

改完代码后,你会遇到另一个问题:返回了一个刚刚被销毁的缓冲区指针。为了解决这个问题,你应该返回一个 std::string

template <typename T>
std::string numberToString(T number) 
{
    std::ostringstream ss;
    ss << number;
    return ss.str();
}

你可以使用std::to_string来实现,因此编写自己的函数是毫无意义的。


如果你没有C++11编译器,那么这并不是毫无意义的,很多人都没有。然而,对于那些有C++11编译器的人来说,这是一个不错的建议。 - shawn1874
@shawn1874 很好...不过,此时此刻,所有旧的编译器都应该很快被淘汰了。天哪,C++14已经进入最后阶段获得批准了。 - Zac Howland

2
那是因为 c_str()是std::string的成员函数,它返回一个const char*
要获取strinstream的基础字符串,必须使用 str()
错误非常明显:

error C2039: 'c_str' : is not a member of 'std::basic_ostringstream

然而,请注意,您正在返回指向某事物(由str()返回的临时字符串的基础数据)的指针,该指针在返回语句后(即在调用代码中)将不存在,并且操纵该指针肯定会导致未定义的行为。
由于您在使用C++,您可以直接返回std::string,并使用输出。
std::cout << numberToString(123);

这样会更安全。


它不会是指向流内部数据的指针,str() 返回流中包含的字符串的副本。无论如何,它仍将是指向临时变量的指针,在该表达式结束时将被销毁。 - Praetorian
@Praetorian 没错!已经更正。 - JBL

2

您想要做什么:

template <typename T>
std::string numberToString(T number) {
    std::ostringstream ss;
    ss << number;
    return ss.str();
}

int main() {
    std::cout << numberToString(123);
    return 0;
}

要获取std::ostringstream中的基础std::string,然后获取std::string中的结果C风格字符串。正如其他人指出的那样,c_str返回的指针会超出作用域,因此必须将其复制到缓冲区或另一个std::string中。如果您坚持使用printf,则在函数调用上使用c_str

printf("%s", numberToString(123).c_str());

更多信息请参见从函数返回“const char *”是否是一个好主意?

这取决于 somestlstring 是什么以及在其中进行了什么操作。

如果它是一个局部变量,那么您正在返回指向在 GetSomeString 完成时被释放的内存的指针,因此它是悬空指针和错误。

所有问题都归结为 somestlstring 的生命周期和您对其执行的操作。.c_str() 返回的指针仅保证在字符串中的下一个可变操作之前有效。所以,如果某些内容在调用 .c_str() 之后并在构造 s 之前更改了 somestlstring,则会出现未定义的行为。

但是,您可以简单地使用 std::to_string

std::string s = std::to_string(123);

我已经这样做了,但现在我的程序没有输出任何内容。出了什么问题? - Tetramputechture
你为什么需要那个 temp 变量呢?直接使用 return ss.str() 就可以了。或者至少使用 temp = ss.str()。你浪费时间创建一个 string,获取它的内部缓冲区并构造另一个 string,这样做没有任何意义。 - Eran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接