Внутренне и о сгенерированном коде существует ли действительно разница между:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
и
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
спасибо...
Внутренне и о сгенерированном коде существует ли действительно разница между:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
и
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
спасибо...
Предполагая, что эти значения являются примитивными типами, то нет, нет никакой разницы. Списки инициализации имеют значение только тогда, когда у вас есть объекты как члены, поскольку вместо инициализации по умолчанию, за которой следует назначение, список инициализации позволяет инициализировать объект до его окончательного значения. Это может быть заметно быстрее.
Вам нужно использовать список инициализации для инициализации постоянных членов, ссылок и базового класса
Когда вам нужно инициализировать константные элементы, ссылки и параметры передачи для конструкторов базового класса, как указано в комментариях, вам нужно использовать список инициализации.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Пример (не исчерпывающий) class/struct содержит ссылку:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
И пример инициализации базового класса, для которого требуется параметр (например, конструктор по умолчанию):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
Да. В первом случае вы можете объявить _capacity
, _data
и _len
как константы:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
Это было бы важно, если вы хотите обеспечить const
-ness этих переменных экземпляра при вычислении их значений во время выполнения, например:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
экземпляры должны быть инициализированы в списке инициализаторов, или базовые типы должны предоставлять общедоступные конструкторы без параметров (какие примитивные типы делают).
Я думаю, что эта ссылка http://www.cplusplus.com/forum/articles/17820/ дает отличное объяснение - особенно для тех, кто не знаком с С++.
Причина, по которой списки intialiser более эффективны, заключается в том, что внутри тела конструктора выполняются только назначения, а не инициализация. Поэтому, если вы имеете дело с нестрочным типом, конструктор по умолчанию для этого объекта уже вызывается до того, как был введен тело конструктора. Внутри тела конструктора вы присваиваете значение этому объекту.
По сути, это вызов конструктора по умолчанию, за которым следует вызов оператору присваивания копий. Список инициализации позволяет вам напрямую вызвать конструктор копирования, и иногда это может быть значительно быстрее (напомните, что список инициализаторов находится перед телом конструктора)
Я добавлю, что если у вас есть члены типа класса без конструктора по умолчанию, инициализация - это единственный способ построить ваш класс.
Большая разница заключается в том, что назначение может инициализировать элементы родительского класса; инициализатор работает только с членами, объявленными в текущем классе.
Зависит от соответствующих типов. Разница аналогична между
std::string a;
a = "hai";
и
std::string a("hai");
где вторая форма - это список инициализации, то есть имеет значение, если тип требует аргументов конструктора или более эффективен с аргументами конструктора.
Реальная разница сводится к тому, как компилятор gcc генерирует машинный код и кладет память. Объясните:
Существуют, конечно, другие способы обработки элементов типа const. Но чтобы облегчить их жизнь, составители компилятора gcc решили установить некоторые правила.
Существует только один способ инициализировать экземпляры базового класса и нестатические переменные-члены и использовать список инициализаторов.
Если вы не укажете базовую или нестационарную переменную-член в списке инициализатора конструктора, то этот элемент или база будут либо инициализированы по умолчанию (если член/база является классом класса не-POD или массивом не- -POD) или оставлено неинициализированным в противном случае.
После ввода тела конструктора все базы или элементы будут инициализированы или оставлены неинициализированными (т.е. они будут иметь неопределенное значение). В конструкторе нет возможности влиять на то, как они должны быть инициализированы.
Возможно, вы сможете назначать новые значения членам в теле конструктора, но невозможно назначить членам const
или членам типа класса, которые были сделаны несвязаемыми, и невозможно перепроверить ссылки.
Для встроенных типов и некоторых пользовательских типов назначение в теле конструктора может иметь тот же эффект, что и инициализация с тем же значением в списке инициализаторов.
Если вы не можете назвать член или базу в списке инициализаторов, и этот объект является ссылкой, имеет тип класса без доступного объявленного пользователем конструктора по умолчанию, const
квалифицирован и имеет тип POD или тип класса POD или массив класса класса POD, содержащий const
квалифицированный член (прямо или косвенно), тогда программа плохо сформирована.
Если вы пишете список инициализаторов, вы делаете все за один шаг; если вы не пишете список инициализаторов, вы сделаете 2 шага: один для объявления и один для присвоения значения.
В конструкторе есть разница между списком инициализации и инициализацией. Рассмотрим ниже код:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
Когда MyClass используется, все члены будут инициализированы до того, как будет выполнен первый оператор в конструкторе.
Но, когда MyClass2 используется, все члены не инициализируются, когда выполняется первый оператор в конструкторе.
В более позднем случае может возникнуть проблема с регрессией, когда кто-то добавляет некоторый код в конструктор, прежде чем инициализируется определенный член.
Вот момент, когда я не видел, чтобы другие ссылались на него:
class temp{
public:
temp(int var);
};
У временного класса нет ctor по умолчанию. Когда мы используем его в другом классе следующим образом:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
код не будет компилироваться, потому что компилятор не знает, как инициализировать obj
, потому что у него есть только явный ctor, который получает значение int, поэтому мы должны изменить ctor следующим образом:
mainClass(int sth):obj(sth){}
Итак, речь идет не только о const и ссылках!