Вызов конструктора для повторной инициализации переменных не работает? - PullRequest
6 голосов
/ 27 марта 2010

Я хотел запустить 1000 итераций программы, поэтому установил счетчик для 1000 в основном. Мне нужно было повторно инициализировать различные переменные после каждой итерации, и поскольку конструктор класса уже записал все инициализации - я решил вызывать это после каждой итерации, чтобы результат каждой итерации сохранялся в переменной main.

Однако, когда я вызвал конструктор, это не имело никакого эффекта ... мне потребовалось некоторое время, чтобы выяснить - но это ничего не инициализировало!

Я создал функцию в точности как конструктор, поэтому у объекта будет своя версия. Когда я позвонил, он все заново инициализировал, как я и ожидал.

int main()
{
 Class MyClass()

 int counter = 0;

 while ( counter < 1000 )
 { stuff happens }

 Class(); // This is how I tried to call the constructor initially.
          // After doing some reading here, I tried:
          // Class::Class(); 
          // - but that didn't work either 
 /* Later I used...
 MyClass.function_like_my_constructor; // this worked perfectly
 */
}

... Может кто-нибудь попытаться объяснить, почему то, что я сделал, было неправильно, или не сработало, или глупо, или что у тебя? Я имею в виду - мысленно, я просто подумал - дерьмо, я могу вызвать этот конструктор и переинициализировать все эти вещи. Вызывают ли конструкторы (в идеале) ТОЛЬКО при создании объекта?

Ответы [ 5 ]

8 голосов
/ 27 марта 2010

Ваша строка Class(); вызывает конструктор класса Class, но вызывает его для создания "временного объекта". Поскольку этот временный объект не используется, строка не имеет никакого полезного эффекта.

Временные объекты (обычно) исчезают в конце выражения, в котором они появляются. Они полезны для передачи в качестве параметров функции или для инициализации других объектов. Почти никогда не бывает полезно просто создать его в одном утверждении. Язык допускает его в качестве допустимого выражения, просто для большинства классов это не так уж и много.

В C ++ нет способа вызвать конструктор для объекта, который уже был построен. Жизненный цикл объекта C ++ - это одна конструкция и одно разрушение. Вот только как это работает. Если вы хотите сбросить объект в течение его жизни, вы сделали правильную вещь, а именно, вызвали функцию для его сброса. В зависимости от вашего класса вам может не понадобиться писать один - оператор присваивания по умолчанию может делать именно то, что вам нужно. Вот тогда временный может пригодиться:

Class myObject;
// ... do some stuff to myObject ...

myObject = Class();

Это обновляет myObject значениями из недавно созданного временного. Это не обязательно самый эффективный из возможных кодов, поскольку он создает временный, затем копирует, а затем уничтожает временный код, а не просто устанавливает поля в их начальные значения. Но если у вас огромный класс, маловероятно, что выполнение всех этих 1000 раз займет заметное количество времени.

Другой вариант - просто использовать новый объект для каждой итерации:

int main() {
    int counter = 0;
    while (counter < 1000) {
        Class myObject;
        // stuff happens, each iteration has a brand new object
    }
}

Обратите внимание, что Class MyClass(); не не определяет объект типа Class, называемый MyClass, и создает его без параметров. Он объявляет функцию MyClass, которая не принимает параметров и возвращает объект типа Class. Предположительно в вашем реальном коде конструктор имеет один или несколько параметров.

5 голосов
/ 27 марта 2010

Что происходит в этой строке, читая ...

Class ();

Это то, что вы на самом деле вызываете конструктор - для временного объекта, который создается с нуля, а затем немедленно уничтожается, поскольку вы ничего с ним не делаете. Это очень похоже на приведение к классу, который создает значение с помощью вызова конструктора, за исключением того, что в этом случае нет значения для приведения, поэтому используется конструктор по умолчанию.

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

Если вы хотите переинициализировать элементы, вызов конструктора не является способом сделать это. Переместите весь свой код инициализации в другой метод и вызовите его из своего конструктора, а вместо этого, если вы хотите выполнить повторную инициализацию.

1 голос
/ 27 марта 2010

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

0 голосов
/ 28 марта 2010

При таких требованиях я обычно пишу clear() (публичный) метод. Я называю это от конструктора, деструктора. Код пользователя может вызывать его в любое время.

class Foo
{
  public:

    Foo() { clear(); }

    ~Foo() { clear(); }

    void clear(); // (re)initialize the private members

  private:

     // private members
 };

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

0 голосов
/ 27 марта 2010

Вы стали жертвой распространенного неправильного чтения c ++. Новый c ++ 0x делает вещи немного понятнее.

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

void foo( int i ) { }
class Foo { };

Foo(10); // construct a temporary object of type foo
foo(10); // call function foo
Foo{10}; // construct a temporary object of type foo in c++0x syntax

Мне кажется, синтаксис c ++ 0x более понятен.

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

MyClass.~Class(); // destruct MyClass
new( &MyClass ) Class;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...