Стандартная компоновка и не копируемое свойство - PullRequest
2 голосов
/ 31 января 2012

C ++ 11, §9 / 7:

A класс стандартной компоновки - это класс, который:

  • не имеет нестатических членов-данных типа нестандартного класса (или массива таких типов) или ссылки,
  • не имеет виртуальных функций и виртуальных базовых классов,
  • имеет одинаковый контроль доступа для всех нестатических элементов данных,
  • не имеет базовых классов нестандартной компоновки,
  • либо не имеет нестатических элементов данных в наиболее производном классе и не более одного базового класса с нестатическими элементами данных, либо не имеет базовых классов с нестатическими элементами данных, и
  • не имеет базовых классов того же типа, что и первый нестатический элемент данных.

Итак, есть ли способ сделать класс со стандартным макетом не подлежащим копированию? Если да, то как?

Частное наследование от boost :: noncopyable не будет работать, потому что это сделало конструктор копирования закрытым (следовательно, не стандартной компоновкой). Реализация boost :: noncopyable выглядит следующим образом:

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

Из-за закрытого раздела это не стандартный класс макета. Также я уверен, что частное наследование нарушает какое-либо стандартное правило размещения.


#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;
}

Вывод:

200
200
2000
2004

Приведенный выше пример показывает, что частное наследование от boost::noncopyable изменяет класс на НЕ совместимый со стандартным макетом. Я не уверен, является ли это ошибкой g ++ (я использую g ++ 4.6.1), или стандарт каким-то образом нарушен.

Ответы [ 2 ]

4 голосов
/ 31 января 2012

Я думаю, здесь есть путаница:

  • на стандартное свойство макета влияют атрибуты (и только атрибуты)
  • На копируемое свойство влияют методы (их наличие, отсутствие и доступность)

Два понятия ортогональны.

UPDATE:

Ниже показано то же поведение, что и 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";
}

Результат 4.

Я полагаю, это из-за:

  • не имеет базовых классов того же типа, что и первый нестатический элемент данных.

Действительно, эксперимент показывает, что введение int a; в D до data не увеличивает его размер. Я думаю, что тот факт, что B наследуется от foo, означает, что data (первый нестатический элемент данных) считается того же типа, что и foo (базовый класс D).

Это приводит к неоднозначности: foo* f = &d будет иметь тот же адрес, что и foo* g = &b.data;, если компилятор не введет это заполнение.

0 голосов
/ 31 января 2012

Есть две вещи, которые нужно сделать, чтобы ваш класс не был копируемым:

  1. Сделать конструктор копирования личным.
  2. Сделать оператор присваивания приватным. (Где ему присваивается другой тип того же вида, что и сам класс).

Вам не нужно наследовать от некоторого класса наддува, просто чтобы получить такое поведение.

И позвольте мне добавить, кому небезразлична какая-то причудливая идея «стандартной компоновки». Запрограммируйте то, что вам нужно, и не поддавайтесь этой теории экстремального пространства.

...