Pergunta

I'm attempting to build a bit of simple logging functionality from scratch, with a stream like '<<' interface, and am running into a bit of compiler issue. Here is the basics of my code:

#include <string.h>
#include <sstream>
#include <iostream>

class Logger
{
public:
    class Buffer
    {
    public:
        Buffer(Logger &parent) : mPar(parent)
        {
        }

        ~Buffer(void)
        {
            mPar.endline(os);
        }

        template<class T>
        Buffer& operator<<(const T& x)
        {
            os << x;
            return *this;
        }

        Logger& mPar;
        std::ostringstream os;
    };

    Buffer write(void)
    {
        return Buffer(*this);
    }

    void endline(std::ostringstream& os)
    {
        std::cout << os.str() << std::endl;
    }
};

int main(int argc, char **argv)
{
    Logger log;

    log.write() << "fred" << 3 << "bob";
}

The errors I'm getting are:

In file included from /usr/include/c++/4.6/ios:45:0,
                 from /usr/include/c++/4.6/istream:40,
                 from /usr/include/c++/4.6/sstream:39,
                 from test.cpp:2:
/usr/include/c++/4.6/bits/ios_base.h: In copy constructor ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’:
/usr/include/c++/4.6/bits/ios_base.h:788:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from test.cpp:2:0:
/usr/include/c++/4.6/sstream: In copy constructor ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’:
/usr/include/c++/4.6/sstream:373:11: note: synthesized method ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ first required here
/usr/include/c++/4.6/streambuf: In copy constructor ‘std::basic_stringbuf<char>::basic_stringbuf(const std::basic_stringbuf<char>&)’:
/usr/include/c++/4.6/streambuf:782:7: error: ‘std::basic_streambuf<_CharT, _Traits>::basic_streambuf(const __streambuf_type&) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_streambuf<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]’ is private
/usr/include/c++/4.6/sstream:60:11: error: within this context
/usr/include/c++/4.6/sstream: In copy constructor ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’:
/usr/include/c++/4.6/sstream:373:11: note: synthesized method ‘std::basic_stringbuf<char>::basic_stringbuf(const std::basic_stringbuf<char>&)’ first required here
test.cpp: In copy constructor ‘Logger::Buffer::Buffer(const Logger::Buffer&)’:
test.cpp:8:8: note: synthesized method ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’ first required here
test.cpp: In member function ‘Logger::Buffer Logger::write()’:
test.cpp:33:22: note: synthesized method ‘Logger::Buffer::Buffer(const Logger::Buffer&)’ first required here

From what I've been able to find so far, the errors are because you can't call the copy constructor on ostringstream. As far as I can tell though, I'm not calling a copy constructor directly, and I'm not copying Buffer, only constructing it in the 'return' statement.

The other interesting thing is that this code compiles fine under Visual Studio 2010 where I knocked it up before integrating it into my application (which is compiled using GCC 4.6.3).

Have I interpreted the issue correctly, and if so - where is the implicit copy, and how do eliminate it?

Foi útil?

Solução

The first problem is that std::ostringstream is non-copyable, and you are trying to create a copy of it while creating a copy of Buffer.

The reason why you are creating a copy of Buffer in this return statement:

return Buffer(*this);

Is that your class Buffer does not have an implicitly-generated move constructor. And the reason why it does not have one, is that Buffer has a user-defined destructor, which inhibits the implicit generation of the move constructor.

You could define one explicitly:

    Buffer(Buffer&& b)
        :
        mPar(b.mPar),
        os(std::move(b.os))
    {
    }

But you should be aware of the fact that some implementations of the Standard Library are not fully compliant, and do not implement the move constructor of std::ostringstream.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top