Standard layout and non-copyable property

1k views Asked by At

C++11, §9/7:

A standard-layout class is a class that:

  • has no non-static data members of type non-standard-layout class (or array of such types) or reference,
  • has no virtual functions and no virtual base classes,
  • has the same access control for all non-static data members,
  • has no non-standard-layout base classes,
  • either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
  • has no base classes of the same type as the first non-static data member.

So, is there a way to make a class with standard layout non-copyable? If yes, how?

Inheriting privately from boost::noncopyable will not work, because it made copy constructor private (hence not a standard layout). The boost::noncopyable's implementation is like this :

  class noncopyable
  {
   protected:
      noncopyable() {}
      ~noncopyable() {}
   private:  // emphasize the following members are private
      noncopyable( const noncopyable& );
      const noncopyable& operator=( const noncopyable& );
  };

Because of the private section, it is not a standard layout class. I am also note sure if private inheritance break any standard layout rule.


#include <boost/noncopyable.hpp>
#include <iostream>
const int N = 50;
struct A
{
    int data[N];
};
struct B : private boost::noncopyable
{
    int data[N];
};
struct C
{
    A data[10];
};
struct D : private boost::noncopyable
{
    B data[10];
};

int main() {
    std::cout<<sizeof(A)<<std::endl;
    std::cout<<sizeof(B)<<std::endl;

    std::cout<<sizeof(C)<<std::endl;
    std::cout<<sizeof(D)<<std::endl;
}

The output is :

200
200
2000
2004

The example above shows that inheriting privately from boost::noncopyable changes the class into NOT standard layout compliant. I am not sure if this is a g++ bug (I am using g++ 4.6.1), or the standard is somehow violated.

2

There are 2 answers

4
Matthieu M. On BEST ANSWER

I think there is a confusion here:

  • the standard layout property is affected by attributes (and only attributes)
  • the copyable property is affected by methods (their presence, absence and accessibility)

The two concepts are orthogonal.

UPDATE:

The following display the very same behavior that boost::noncopyable:

#include <iostream>

struct foo {};

struct B : foo { int data; };

struct D : foo { B data; };

int main() {
  D d;
  std::cout << (char*)(&d.data) - (char*)(&d) << "\n";
}

The result is 4.

I believe this is because of:

  • has no base classes of the same type as the first non-static data member.

Indeed, experiment shows that introducing a int a; in D prior to data does not increases its size. I think that the fact that B inherits from foo means that data (first non-static data member) is considered to be the same type as foo (base class of D).

This leads to an ambiguity: foo* f = &d would have the same address as foo* g = &b.data; if the compiler did not introduce this padding.

4
C.J. On

There are two things you need to do to make your class non copyable:

  1. Make the copy constructor private.
  2. Make the assignment operator private. (Where it gets assigned another type of the same kinds as the class itself).

You don't need to inherit from some boost class just to get that behavior.

And may I add, who cares about some fancy 'standard layout' idea. Program what you need and don't succumb to this extreme space theory.