Создание объекта C ++ в стеке, изо всех сил стараясь не выделять - PullRequest
2 голосов
/ 12 октября 2010

Предположим, у меня есть класс

    class A {
      public:
      A(int i);
      ~A();
      private:
      B b;   // Want <- this guy to be constructed with i in A's constructor!
    };
. Я хочу, чтобы b конструировался в конструкторе с конкретными параметрами, которые не известны, пока не будет построен A.Если бы я сделал следующее в конструкторе А:
    A::A(int i) {   
      B b(i);
      // Or even if I try to do b = B::B(i);
    }

Я бы заметил, что b get выделяется дважды в стеке!ахххх.

Затем я обнаружил, что в конструкторе А я могу сделать следующее:

A::A() : b(B::B(7)) {

}

И b выделяется в стеке только один раз!

Но этодовольно неуклюжийУ кого-нибудь есть идея получше?Помните, конструктор должен вызываться только один раз!

Является ли это стандартным способом НЕ-динамического распределения объектов с важными параметрами?Что если мы сможем засунуть конструкцию b в этот причудливый список аргументов !?Вы вынуждены либо динамически распределять, либо создавать ДВАЖДЫ в стеке!

Бонус Вопрос: Когда b освобождается?Это после или прямо перед деструктором А

Ответы [ 3 ]

7 голосов
/ 12 октября 2010

Извините, но у вас все неправильно.

Что вам нужно сделать, это подобрать книгу C ++ хорошего новичка .Это настолько фундаментальная часть языка, что, если вы этого не понимаете, вы будете испытывать трудности при работе с нетривиальным кодом C ++.

Это, как говорится, когда объект собирается быть созданвсе подобъекты будут созданы первыми.Если вам нужно передать параметры этим конструкторам подобъектов, вам нужно создать так называемый список инициализаторов:

A::A(int i) : b(i) {}

Материал, следующий за двоеточием и перед первой фигурной скобкой, является списком инициализаторов.Только конструкторы могут иметь их.Здесь происходит то, что мы передаем значение i в конструктор подобъекта b.Это происходит за до того, как будет вызван конструктор для A!

Итак, для вашего случая порядок построения:

  1. Подобъект b
  2. Сам объект A

Порядок уничтожения - совершенно противоположный процесс.

3 голосов
/ 12 октября 2010

делает

A::A() : b(7) { }

не работает?

Редактировать: я на работе, поэтому позже сделаю более полное редактирование, используя некоторые профили, чтобы узнать, что делает gcc с w.r.t. открепление. Я подозреваю, что nobar прав, и все освобождение происходит сразу.

b(B::B(7)) работает так же, как и b(7), поскольку B::B(7) создает временную переменную B. b затем копируется из этого временного объекта. Приличный оптимизирующий компилятор должен быть в состоянии сократить второй случай до первого, но:

  1. b(7) более идиоматичен - другие программисты на C ++ распознают это легче
  2. Вы действительно не знаете наверняка, что будет делать компилятор.
  3. если B не является копируемым или дорогостоящим для копирования-конструирования, вы можете не захотеть иметь дело с дополнительными издержками, если, как и большинство, отключаете оптимизацию для отладки.
0 голосов
/ 12 октября 2010

Требуется лишь небольшая модификация вашей программы, чтобы продемонстрировать порядок построения и разрушения.

   #include <iostream>

   using std::cerr;

class B
   {
public:
   B( int ) { cerr<<"B()\n"; ;}
   ~B() { cerr<<"~B()\n"; }
   };

class A
   {   
   B b;
public:
   A( int i ) : b(i) { cerr<<"A()\n"; }
   ~A() { cerr<<"~A()\n"; }
   };

int main()
   {
   A a(7);
   }

Вот вывод:

$ make destructor_order && ./destructor_order
B()
A()
~A()
~B()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...