4

I have a ostringstream variable which contains some data. I want to get set a char * pointer to the data inside the ostringstream.

If I do the following:

std::ostringstream ofs;
.....
const char *stam = (ofs.str()).c_str();

There is a copy of the content of the string in ofs. I want to get a pointer to that content without a copy.

Is there a way to do so?

Shay
  • 633
  • 2
  • 11
  • 27
  • 5
    You don't have a copy of the string there. You have a dangling pointer. I know what you are after though, and unfortunately, you are out of luck. There is no way to get the string out of `ostringstream` without a copy. – Benjamin Lindley Jun 19 '13 at 16:58
  • what is a dangling pointer? – Shay Jun 19 '13 at 16:59
  • 2
    A pointer to a destroyed object. `ofs.str()` returns a copy of the string, you then call `c_str()` on this copy. But the copy is destroyed at the end of the statement, and so `stam` is left invalid (dangling). In order to not have a dangling pointer, you need to capture the actual string in a string object, so it survives: `std::string str = ofs.str(); stam = str.c_str();` – Benjamin Lindley Jun 19 '13 at 17:01
  • if I write: std::string& str = ofs.str(); char *stam = str.c_str(); Is there a copy here? – Shay Jun 19 '13 at 17:04
  • That's not legal C++, because you are trying to bind a non-const reference to a temporary. The problem is that `ostringstream::str` returns by value, so there's no way of getting around the copy. There are interested parties in the standards discussions trying to fix this discrepancy, but unfortunately, we have to live with it for now, or use other facilities for string building. – Benjamin Lindley Jun 19 '13 at 17:07
  • doesnt a const reference extend the life of the temp variable? – Shay Jun 19 '13 at 17:12
  • Yes, a const reference will do that. You can do `const std::string & str = ofs.str();` -- But this doesn't really buy you anything. There is still a copy being made from the ostringstream's internal string to the return value. And the other copy, from the return value to the variable, will be eliminated by copy elision anyway. – Benjamin Lindley Jun 19 '13 at 17:14

2 Answers2

4

This actually answers the question... took a while but I wanted to do it for the same reasons (efficiency vs portability is fine for my situation):

class mybuf : public std::stringbuf {
public:
    // expose the terribly named end/begin pointers
    char *eback() {
        return std::streambuf::eback();
    }
    char *pptr() {
        return std::streambuf::pptr();
    }
};


class myos : public std::ostringstream {
    mybuf d_buf;
public:
    myos() {
        // replace buffer
        std::basic_ostream<char>::rdbuf(&d_buf);
    }
    char *ptr();
};

char *myos::ptr() {
    // assert contiguous
    assert (  tellp() == (d_buf.pptr()-d_buf.eback()) );
    return d_buf.eback();
}

int main() {
    myos os;
    os << "hello";
    std::cout << "size: " << os.tellp()  << std::endl;
    std::string dat(os.ptr(),os.tellp());
    std::cout << "data: " << dat  << std::endl;
}

This points to, yet again, the deeper, underlying problem with the standard library - a confusion between contracts and "safety". When writing a messaging service, I need a library with efficient contracts... not safety. Other times, when writing a UI, I want strong safety - and cares less about efficiency.

Erik Aronesty
  • 11,620
  • 5
  • 64
  • 44
1

Although you can't get a pointer to the character buffer in the ostringstream, you can get access to its characters without copying them if you switch to using stringstream. A stringstream allows input and output (reading from and writing to the stream), whereas ostringstream allows only output (writing to the stream). Example:

std::stringstream ss;
ss << "This is a test.";

// Read stringstream from index 0.  Use different values to look at any character index.
ss.seekg(0);

char ch;
while (ss.get(ch)) {                  // loop getting single characters
    std::cout << ch;
}

ss.clear(); // Clear eof bit in case you want to read more from ss

This site has a pretty good overview of stringstreams and what you can do with them.

Winter Dragoness
  • 1,327
  • 12
  • 13