Copy and destructor builders in C ++ 98

4

This is a small wrapper for a system of binnacles; the used library is in C, so I have simply added an interface to std::stream :

#include <sstream>
#include <iostream>

class ILogger;

class Stream {
  friend class ::ILogger;

  std::stringstream m_ss;

  Stream( const Stream & );
  Stream &operator=( const Stream & );

public:
  ~Stream( ) {
    std::cout << m_ss.str( ) << std::endl;
  }
  inline Stream( ) { }

  template< typename T > inline Stream &operator<<( const T &val ) {
    m_ss << val;

    return *this;
  }
};

class ILogger {
public:
  template< typename T > inline Stream operator<<( const T &val ) {
    Stream s;

    s << val;

    return s;
  }
};

int main( ) {
  ILogger log;

  log << "Hola" << " mundo " << "cruel";

  return 0;
}

The library uses functions at printf , so we just generate a string using a std::stringstream using an auxiliary class and, when destroying the instance of that auxiliary, is when you call the true function of C.

To my surprise, the code works!

I say this because I expected a compilation error, having Stream::Stream( const Stream & ) declared as private . I hoped that, when leaving the field, the copy constructor and the destructor would be invoked. I have not said it yet, but this is for C ++ 98.

template< typename T > inline Stream operator<<( const T &val ) {
  Stream s;

  s << val;

  return s; // salimos del ámbito. 's' se pierde
}

I am compiling with g++ 7.2 , with the order g++ -std=c++98 -Wall -Wextra -pedantic .

  • The question is: Is this the expected behavior, or is it a feature of my compiler? Can I trust is to get the same results in older compilers?

Note : The goal of that code is to run on very old machines, with SDK no longer supported ... and I do not want last-minute surprises: -O

    
asked by Trauma 03.03.2018 в 23:02
source

1 answer

4

Where is the surprise? That's what friends are for!

class Stream {
  friend class ::ILogger;

  /* codigo */
}

By having Stream as friend ILogger , it will have access to even the private sections of Stream , both variables, and functions, including special functions.

  

Is this the expected behavior, or is it a feature of my compiler?

It is not a compiler characteristic, it is an intrinsic characteristic of the language, it is indicated by the standard in section 14.3 (my translation):

  

14.3 Friends [class.friend]

     
  • The friend of a class is a function or class that is granted permission to use the private and protected members of that class. A class specifies its friends, if any, through friend declarations. These statements give special rights of access to the Maigos, but do not make friends are members of the classes with which they have friendship.
  •   
      

    Can I trust is to get the same results in older compilers?

    Yes. The following code behaves like yours:

    class C
    {
        friend struct X;
        void privada() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
    public:
        void publica() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
    };
    
    struct X
    {
        /* X puede usar C::privada, porque C se lo permite
        con su amistad. */
        void f() { C c; c.privada(); }
    };
    

    And this fails:

    struct Y
    {
        /* Error de compilación, Y no puede usar C::privada
        porque C no le otorgó amistad. */
        void f() { C c; c.privada(); }
    };
    
      

    I expected that, when leaving the scope, the copy constructor and the destructor would be invoked.

    This is true in some cases, and in others the compiler applies an optimization known as "Return Value Optimization" (OVR) 1 , this optimization is that the compiler can decide to build a object outside the function that creates it if it detects that doing so does not cause any side effects, thus omitting a copy. This optimization has been integrated into the language almost from the beginning, so in C ++ 98 it is available.

    You may get the behavior you expected if you deactivate all of your compiler's optimizations.

  • Known in English as "Return Value Optimization" RVO.
  • answered by 04.03.2018 в 01:09