2
votes

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
Why do you thing that making the copy constructor private will make the class not be standard layout?Mankarse
@Mankarse So, can standard layout classes have private copy constructor?BЈовић
Functions are not "non-static data members". So assuming you've quoted the definition correctly, the "private section" doesn't make noncopyable non-standard layout.Steve Jessop
I added an example where a class inheriting from boost::noncopyable including standard layout class (again inheriting from boost::noncopyable) is not a standard layout class. Can you explain this?BЈовић
@VJovic : The size of the type increasing is orthogonal with being standard-layout (§9.2/20 specifically allows it) -- GCC just isn't applying the empty base optimization. If you want to check whether something is standard-layout, don't look at the size, use the type trait for it (std::is_standard_layout<>).ildjarn

2 Answers

4
votes

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.

0
votes

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.