2016-04-04 3 views
2

J'ai l'exemple de classe suivant, simplifié d'un projet plus grand. Il est basé sur un cadre de journalisation qui utilise la portée de l'enregistreur pour terminer une entrée de journal dans le destructeur.Pourquoi un objet contenant un membre ostringstream ne peut-il pas être construit?

Le code ci-dessous ne compilera pas car le constructeur est une fonction supprimé implicitement (edit: pas vrai), qui semble avoir quelque chose à voir avec l'objet std::ostringstream. Je suis confus à ce sujet parce que je pense que je devrais être capable de construire directement un std::ostringstream, ce qui signifierait que je devrais être capable de construire directement un objet Container.

#include <iostream> 
#include <sstream> 

class Container { 
    public: 
    std::ostringstream bufferStream; 

    public: 
    Container(); // constructor 
    ~Container(); 
}; 

Container::Container() { 
    bufferStream << "Hello "; 
} 

Container::~Container() { 
    std::cout << bufferStream.str() << " [end]" << std::endl; 
} 

// === Main method === 

int main() { 

    Container().bufferStream << "world"; // works fine 

    {          // causes tons of compiler errors 
     Container cont = Container(); 
     cont.bufferStream << "world!"; 
    } 

    return 0; 
} 

Notez que la ligne «fonctionne bien» fait juste cela. Il semble instancier un objet anonyme Container, qui contient un nouveau std::ostringstream, qui peut être directement accédé à la sortie "monde". Le Container crée lui-même la partie "Bonjour" du message et son destructeur vide le tampon.

Pourquoi la deuxième partie, dans laquelle l'objet Container est nommé et enregistré, ne fonctionne-t-elle pas correctement? Voici un exemple des erreurs que j'ai:

error.cpp: In function ‘int main()’: 
error.cpp:28:36: error: use of deleted function ‘Container::Container(const Container&)’ 
     Container cont = Container(); 
            ^
error.cpp:4:7: note: ‘Container::Container(const Container&)’ is implicitly deleted because the default definition would be ill-formed: 
class Container { 
    ^
error.cpp:4:7: error: use of deleted function ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’ 
In file included from error.cpp:2:0: 
/usr/include/c++/4.8/sstream:387:11: note: ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’ is implicitly deleted because the default definition would be ill-formed: 
    class basic_ostringstream : public basic_ostream<_CharT, _Traits> 

... et ainsi de suite.

+0

Euh, ce n'est pas dupe de [cette question] (http://stackoverflow.com/q/3442520/2069064). – Barry

Répondre

8

Cela fonctionne très bien:

Container cont; 
cont.bufferStream << "world!"; 

Mais ceci:

Container cont = Container(); 

implique le constructeur de copie. std::ostringstream n'est pas copie-constructible ce qui rend Container non copiable-constructible, d'où le message d'erreur parlant de comment Container::Container(const Container&) est implicitement supprimé en raison de std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&) étant implicitement supprimé.

Notez que même si cette copie est élue, une exigence d'élision de copie/déplacement est que la copie/le déplacement doit être possible au départ.

+0

Parfait. Ainsi, l'instruction correcte 'Container cont;', construit le conteneur mais ne le copie pas. Mon fond de Java montre! –

+1

... et il appelle le constructeur de copie car le destructeur fourni par l'utilisateur supprime le constructeur de déplacement implicite. –

2

Comme Barry l'a expliqué, le ostringstream n'est pas constructible. En tant que constructeur de copie par défaut, copy-construit membre par membre, il ne peut pas être généré ici. Toutefois, si vous suivez les instructions rule of three, vous créez un constructeur de copie (et également un opérateur d'affectation de copie), doing what is needed pour la chaîne strings. Ensuite, il travaillerait:

class Container { 
    ... 
    Container(const Container&); //Copy constructor 
}; 

Container::Container(const Container &c) { 
    bufferStream << c.bufferStream.rdbuf(); 
} 

Online demo