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;
}

My error:

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>          ]

Why doesn't this work?

4
  • 1
    Documentation: en.cppreference.com/w/cpp/io/basic_ostringstream Commented Dec 20, 2013 at 20:57
  • 2
    You cant get the const char* ( c_str() ) from a temporary string. Once you return from the numberToString your stringstream will be destroyed and its underlying std::string will be destroyed also. When you invoke c_str() it will return a pointer to something that is valid only through the std::string life. I suggest working with std::string, since it is a object (not a pointer) it will be copied when needed. Commented Dec 20, 2013 at 20:59
  • 4
    FYI, the standard library offers this functionality, there's no need to write a function for it. en.cppreference.com/w/cpp/string/basic_string/to_string Commented Dec 20, 2013 at 21:01
  • You read the documentation, hein? ... Commented Dec 20, 2013 at 21:07

4 Answers 4

7

c_str is a member of std::string, not ostringstream. If you want to get a string out of the stream, use str(). Note, however, that returning a const char* from that string is wrong - the string will go out of scope before you can use the const char*. Therefore, have your function return a string (or have it get a buffer to write to):

template <typename T>
std::string numberToString(T number) {
    std::ostringstream ss;
    ss << number;
    return ss.str();
}
Sign up to request clarification or add additional context in comments.

Comments

4

c_str() does not exist for std::ostringstream. What you meant was:

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

After you make that change, you will have another problem: you will be returning a pointer to a buffer that was just destroyed. To fix that, you should return a std::string:

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

Which you can do with std::to_string already, so it is really pointless to write your own function.

2 Comments

It isn't pointless if you don't have a C++11 compiler, and many people do not. However, it is a nice recommendation for people who do have a c++11 compiler.
@shawn1874 Fair enough ... though, at this point, all the old compilers should be phasing out quickly. Hell, C++14 is in its final stages of being approved.
2

That's because c_str() is the member function of std::string which returns a const char*.

To get the underlying string of a strinstream, you must use str().

The error was pretty much self explanatory:

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

Note however that you're returning a pointer to something (the underlying data of the temporary string returned by str()) that will not exist after the return statement (i.e. in the calling code) and that manipulating that pointer will quite sureley end up in undefined behavior.

As you are in C++, you could rather return the std::string directly, and output it with

std::cout << numberToString(123);

which would be safer.

2 Comments

It won't be a pointer to the stream's internal data, str() returns a copy of the string contained within the stream. Regardless, it will still be a pointer to a temporary that will be destroyed at the end of that expression.
@Praetorian Right! Corrected.
2

You want to do:

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

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

To get the underlying std::string in std::ostringstream, and then the resulting c-style string in std::string. As others have pointed out, the pointer returned by c_str goes out of scope, and therefore you must copy it to a buffer or to another std::string. If you insist on using printf, then use c_str on the function call:

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

For more information, see Is it a good idea to return " const char * " from a function?

Depending on what somestlstring is and what is being done there.

If it is a local variable you are returning a pointer into memory that is being released when GetSomeString completes, so it is a dangling pointer and an error.

It all boils down to the lifetime of somestlstring and the operations you perform on it. The pointer returned by .c_str() is guaranteed to be valid only up to the next mutating operation in the string. So if something changes somestlstring from the call to .c_str() and before s is constructed you will be in undefined behavior land.

However, you can simply use std::to_string.

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

2 Comments

I did that, but now my program isn't outputting anything. What's wrong?
Why do you need that temp for? Just go ahead and return ss.str(). Or at least do temp = ss.str(). Your wasting time for nothing creating a string, getting its internal buffer and constructing yet another string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.