Должен ли я использовать список инициализаторов или выполнять присваивания в моих конструкторах C ++? - PullRequest
9 голосов
/ 19 апреля 2011
class Node
{
public:

    Node *parent; // used during the search to record the parent of successor nodes
    Node *child; // used after the search for the application to view the search in reverse

    float g; // cost of this node + it's predecessors
    float h; // heuristic estimate of distance to goal
    float f; // sum of cumulative cost of predecessors and self and heuristic

    Node() :
            parent( 0 ),
            child( 0 ),
            g( 0.0f ),
            h( 0.0f ),
            f( 0.0f )
    {
    }

    UserState m_UserState;
};

Почему мы должны использовать конструктор

    Node() :
            parent( 0 ),
            child( 0 ),
            g( 0.0f ),
            h( 0.0f ),
            f( 0.0f )
    {
    }

вместо

    Node()
    {
        parent = null;
        child = null;
        g = 0.0f;
        h = 0.0f;
        f = 0.0f;
    }

Спасибо:)

Ответы [ 5 ]

14 голосов
/ 19 апреля 2011

Для простых старых данных (POD) это имеет небольшое преимущество, но как только вы начинаете использовать ссылки или составлять классы, это имеет значение:

class Foo {
    Bar bar;

  public:
    // construct bar from x
    Foo(int x) : bar(x) { }
};

против

Foo::Foo(int x)
{
    // bar is default-constructed; how do we "re-construct" it from x?
    bar = x;  // requires operator=(int) on bar; even if that's available,
              // time is wasted default-constructing bar
}

Иногда у вас даже не будет способа «перестроить» объект после его создания, поскольку класс может не поддерживать сеттеры или operator=.const члены, безусловно, не могут быть "восстановлены" или сброшены:

class FooWithConstBar {
    const Bar bar;

  public:
    Foo(int x) {
        // bar is cast in stone for the lifetime of this Foo object
    }
};

Редактировать : спасибо @Vitus за указание на проблему со ссылками.

6 голосов
/ 19 апреля 2011

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

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

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

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

Теперь тогда - почему бы вам не использовать его?

3 голосов
/ 19 апреля 2011
2 голосов
/ 19 апреля 2011

В основном из-за проблем с производительностью.

Обсуждается здесь .

1 голос
/ 19 апреля 2011

Основная причина - валидность объекта и инварианты класса. Другая причина - простота использования.

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

...