Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 21.04.17 06:56
Оценка:
Привет всем!

Почему нельзя писать так

class A {
public:
   void A() {}
};

?

Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?
Re: Почему нельзя писать void ctor();
От: SaZ  
Дата: 21.04.17 08:09
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Привет всем!


МР>Почему нельзя писать так


МР>
МР>class A {
МР>public:
МР>   void A() {}
МР>};

МР>?

МР>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?


Потому что конструктор не возвращает значений. В том числе типа void. Да, void тоже имеет тип.
Re: Почему нельзя писать void ctor();
От: Videoman Россия https://hts.tv/
Дата: 21.04.17 08:29
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Привет всем!


МР>Почему нельзя писать так


МР>
МР>class A {
МР>public:
МР>   void A() {}
МР>};

МР>?

Как уже ответили он не имеет возвращаемого типа, совсем никакого.
Т.е. вот так написать можно:
void FuncA();
void FuncB() 
{
return FuncA();
}

а вот так нельзя:
class A
{
//...
};
void FuncB()
{
return A();
}
Отредактировано 21.04.2017 8:35 Videoman . Предыдущая версия .
Re: Почему нельзя писать void ctor();
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.04.17 08:50
Оценка: 2 (1)
Здравствуйте, Максим Рогожин, Вы писали:

МР>Почему нельзя писать так


МР>class A {

МР>public:
МР> void A() {}
МР>};
МР>?

Страуструп писал, что это для подчёркивания того факта, что конструктор никогда не зовётся напрямую.

МР>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?


Вот принятое в Unix ABI, например, знает

  <ctor-dtor-name> ::= C1    # complete object constructor
           ::= C2    # base object constructor
           ::= C3    # complete object allocating constructor
           ::= D0    # deleting destructor
           ::= D1    # complete object destructor
           ::= D2    # base object destructor


В этом случае тот конструктор, что с C3, аллоцирует память и возвращает адрес объекта, а те, что C1 и C2, получают первым скрытым параметром адрес объекта и ничего не возвращают.

Больше отличий нет, остальное идентично обычной функции.

Для MSVC правил не знаю, могут быть хитрости.
The God is real, unless declared integer.
Re[2]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 21.04.17 08:59
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Т.е. вот так написать можно:

V>
V>void FuncA();
V>void FuncB() 
V>{
V>return FuncA();
V>}
V>

V>а вот так нельзя:
V>
V>class A
V>{
V>//...
V>};
V>void FuncB()
V>{
V>return A();
V>}
V>


Это понятно. Но я думал, что void как раз и означает что функция не возвращает СОВСЕМ НИКАКОГО значения. Это не так? Раз это не так, то отличается ли организация вызова конструктора от вызова обычных функций, например таких:

int f(int x) { return x*x; }
void g() { return; }


Я имею ввиду является ли трансляция C++ вызова конструктора в ассемблерный код каким-то специальным частным случаем, который обрабатывается способом отличным от способа, которым транслируются вышеприведенные функции int f(int) и void g(), например?
Re[2]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 21.04.17 09:07
Оценка:
Здравствуйте, SaZ, Вы писали:

SaZ>Потому что конструктор не возвращает значений. В том числе типа void. Да, void тоже имеет тип.


А вот функция

int g(void) { 
   return 0;
}

принимает какие-нибудь значения? Нет. Так в чем разница между void и отсутствием значений (возвращаемых или принимаемых)?
Re[3]: Почему нельзя писать void ctor();
От: rg45 СССР  
Дата: 21.04.17 09:10
Оценка: 2 (1)
Здравствуйте, Максим Рогожин, Вы писали:

МР>Это понятно. Но я думал, что void как раз и означает что функция не возвращает СОВСЕМ НИКАКОГО значения. Это не так? Раз это не так, то отличается ли организация вызова конструктора от вызова обычных функций, например таких:

МР>
МР>int f(int x) { return x*x; }
МР>void g() { return; }
МР>

МР>Я имею ввиду является ли трансляция C++ вызова конструктора в ассемблерный код каким-то специальным частным случаем, который обрабатывается способом отличным от способа, которым транслируются вышеприведенные функции int f(int) и void g(), например?

Говорить об организации вызова и кодогенерации можно лишь в привязке к каким-то конкретным компиляторам и платформам. То есть это уже детали реализации, но никак не свойства самомго языка, описанные в стандарте. Исходя из самых общих соображений, вряд ли можно придумать какие-то причины, по которым кодогенерация конструктров может принципиально отличаться от кодогенерации функций с типом результата void. При этом синтаксис и семантика имеют известные существенные отличия.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 21.04.2017 9:12 rg45 . Предыдущая версия .
Re[3]: Почему нельзя писать void ctor();
От: Videoman Россия https://hts.tv/
Дата: 21.04.17 09:26
Оценка: 2 (1)
Здравствуйте, Максим Рогожин, Вы писали:

МР>Это понятно. Но я думал, что void как раз и означает что функция не возвращает СОВСЕМ НИКАКОГО значения. Это не так? Раз это не так, то отличается ли организация вызова конструктора от вызова обычных функций, например таких:


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

МР>Я имею ввиду является ли трансляция C++ вызова конструктора в ассемблерный код каким-то специальным частным случаем, который обрабатывается способом отличным от способа, которым транслируются вышеприведенные функции int f(int) и void g(), например?


Может является, а может и нет. Вы можете посмотреть ассемблерный листинг, если интересно.
Re[2]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 22.04.17 07:57
Оценка:
Здравствуйте, netch80, Вы писали:

N>Страуструп писал, что это для подчёркивания того факта, что конструктор никогда не зовётся напрямую.


Мужики, еще немного занудства) Учитывая все сказанное, а почему тогда разрешен следующий синтаксис?

class A {
public:
   A(int);
};

A obj = A(1024);

Глядя на эту запись можно подумать, что здесь конструктор именно зовется напрямую и возвращает значение, аналогично записи

A obj = createObject(1024);
Re[3]: Почему нельзя писать void ctor();
От: rg45 СССР  
Дата: 22.04.17 09:34
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>
МР>A obj = A(1024);
МР>

МР>Глядя на эту запись можно подумать, что здесь конструктор именно зовется напрямую и возвращает значение, аналогично записи
МР>
МР>A obj = createObject(1024);
МР>


Эти две записи похожи лишь формально. Только в первом случае это является не возвращением значения, а прямым конструированием объекта в правой части инициализатора. Это то же самое выражение, которое используется в операторе return в функции createObject:

A createObject(int value)
{
  return A(value);
}
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: Почему нельзя писать void ctor();
От: Masterspline  
Дата: 22.04.17 09:55
Оценка:
МР>Я имею ввиду является ли трансляция C++ вызова конструктора в ассемблерный код каким-то специальным частным случаем, который обрабатывается способом отличным от способа, которым транслируются вышеприведенные функции int f(int) и void g(), например?

Функция она и в Африке функция, даже если она — конструктор. Отличаются они только соглашениями вызова функций. Вот посмотри тут, например, calling conventions. Для конструктора нет особого типа функции, т.е. это примерно то, что ты думаешь. Однако, как тут уже указали, синтаксис и семантика конструктора отличаются от обычной функции, поэтому, реализация тоже может отличаться. В результате реализаций конструкторов несколько (опять же как уже написали) с выделением памяти, без него, другие варианты. Таким образом, в коде конструктора оказывается не только тот код, который написан в исходном файле.

P.S. Для виртуальных функций, кстати, тоже нет "особого" типа. Вполне себе обычные функции-члены, только у каждого класса есть еще таблица виртуальных функций (в стандарте реализация не прописана, но все компиляторы делают через таблицу виртуальных функций).
Отредактировано 22.04.2017 10:00 Ssd13 . Предыдущая версия .
Re[3]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 22.04.17 11:25
Оценка:
Для чего запрещать конструктору возвращать даже void, но при этом разрешать следующий синтаксис?

class A {
public:
  A(int);
};

A obj = A(1024);
Re[4]: Почему нельзя писать void ctor();
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 05:43
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Для чего запрещать конструктору возвращать даже void, но при этом разрешать следующий синтаксис?


МР>class A {

МР>public:
МР> A(int);
МР>};

МР>A obj = A(1024);


А почему этот синтаксис надо запрещать? Вы тут создали безымянный объект типа A и затем скопировали его в obj. Это другое, чем просто написать A obj(1024);.

Компилятор, скорее всего, соптимизирует это в простую инициализацию (если ему не запретить созданием своих конструкторов копирования и перемещения, или введением в A нетривиальных полей), но это не меняет, что изначально это разные вещи.
The God is real, unless declared integer.
Re[5]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 24.04.17 11:26
Оценка:
Здравствуйте, netch80, Вы писали:

N>А почему этот синтаксис надо запрещать?


Потому, что конструктор это функция, которая не возвращает никаких значений. Вот, например

void createObject(int index) {
   A(index); 
}

A obj = createObject(1024); // так же нельзя написать.
A obj = A(1024);            // значит и так нельзя писать... Потому, что функция-конструктор,
                            // с точки зрения синтаксиса, похожа на функцию createObject(int) тем, 
                            // что у нее нет возвращаемого значения.
Re[6]: Почему нельзя писать void ctor();
От: rg45 СССР  
Дата: 24.04.17 14:42
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

N>>А почему этот синтаксис надо запрещать?

МР>Потому, что конструктор это функция, которая не возвращает никаких значений. Вот, например
МР>
МР>A obj = A(1024);            // значит и так нельзя писать... Потому, что функция-конструктор,
МР>                            // с точки зрения синтаксиса, похожа на функцию createObject(int) тем, 
МР>                            // что у нее нет возвращаемого значения.
МР>


Ты сам себя загоняешь в заблуждение, пытаясь рассматривать это выражение как значение, возвращаемое функцией. В то время как никто никого здесь не возвращает — это прямое конструировние объекта имя типа которого задается конструктором. Это по смыслу то же самое что и
int obj = int(1024);

Нет здесь никакого возвращаемого значения, видишь?

Сам по себе конструктор — это всего лишь процедура, единственная задача которой сконструировать объкт в заданной области памяти. Указатель на эту область памяти передается конструктору неявно, и доступна эта область памяти внутри конструктора как this. Никаких значений он возвращать не может в принципе, потому что один и тот же конструктор может вызываться:

для создания rvalue объекта во временной области памяти:
const auto& obj = A(1024);
aFunction(A(1024) + A(42));

в статической или автоматической:
A obj(1024);

в динамической:
A* obj = new A(1024);

а также в любой неизвестной:
new(aPointer) A(1024);

И это все одна и та же процедура! Как она может что-то возвращать при таком разнообразии сценариев использования?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 24.04.2017 15:19 rg45 . Предыдущая версия . Еще …
Отредактировано 24.04.2017 15:18 rg45 . Предыдущая версия .
Отредактировано 24.04.2017 15:11 rg45 . Предыдущая версия .
Отредактировано 24.04.2017 14:42 rg45 . Предыдущая версия .
Re[2]: Почему нельзя писать void ctor();
От: MShura  
Дата: 24.04.17 17:15
Оценка:
N>Для MSVC правил не знаю, могут быть хитрости.

В MSVC конструктор возвращает указатель на себя (в rax)
Re[7]: Почему нельзя писать void ctor();
От: CRT  
Дата: 25.04.17 13:16
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Максим Рогожин, Вы писали:


N>>>А почему этот синтаксис надо запрещать?

МР>>Потому, что конструктор это функция, которая не возвращает никаких значений. Вот, например
МР>>
МР>>A obj = A(1024);            // значит и так нельзя писать... Потому, что функция-конструктор,
МР>>                            // с точки зрения синтаксиса, похожа на функцию createObject(int) тем, 
МР>>                            // что у нее нет возвращаемого значения.
МР>>


R>Ты сам себя загоняешь в заблуждение, пытаясь рассматривать это выражение как значение, возвращаемое функцией. В то время как никто никого здесь не возвращает — это прямое конструировние объекта имя типа которого задается конструктором.


Это выглядит как значение возвращенное функцией. А затем присвоенное с помощью оператора присвоения.
По идее, такое конструирование — это избыточность в языке, достаточно было оставить
A obj(1024);


И эта избыточность запутывает
Отредактировано 25.04.2017 13:19 CRT . Предыдущая версия . Еще …
Отредактировано 25.04.2017 13:19 CRT . Предыдущая версия .
Отредактировано 25.04.2017 13:17 CRT . Предыдущая версия .
Re[4]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 25.04.17 19:55
Оценка:
Здравствуйте, rg45, Вы писали:

R>Говорить об организации вызова и кодогенерации можно лишь в привязке к каким-то конкретным компиляторам и платформам. То есть это уже детали реализации, но никак не свойства самомго языка, описанные в стандарте. Исходя из самых общих соображений, вряд ли можно придумать какие-то причины, по которым кодогенерация конструктров может принципиально отличаться от кодогенерации функций с типом результата void. При этом синтаксис и семантика имеют известные существенные отличия.


Есть конструкторы полей и баз, в том числе и виртуальных, соответственно, есть порядок вызова и обработка исключений во всех этих конструкторах, всего этого нет в обычной функции/методе.
Кроме того, соглашение о вызове у метода и функции обычно разные, у деструктора/конструктора они тоже могут быть своими, особенными...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 25.04.17 20:02
Оценка:
Здравствуйте, netch80, Вы писали:

N>Компилятор, скорее всего, соптимизирует это в простую инициализацию (если ему не запретить созданием своих конструкторов копирования и перемещения, или введением в A нетривиальных полей), но это не меняет, что изначально это разные вещи.


В этом месте компилятор всегда может пропускать конструктор копии, но обязан проверять его доступность...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 25.04.17 20:09
Оценка:
Здравствуйте, rg45, Вы писали:

R>И это все одна и та же процедура! Как она может что-то возвращать при таком разнообразии сценариев использования?


Ещё создание поля, базы и элемента массива забыл.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Почему нельзя писать void ctor();
От: rg45 СССР  
Дата: 25.04.17 22:33
Оценка: +1
Здравствуйте, CRT, Вы писали:

CRT>Это выглядит как значение возвращенное функцией. А затем присвоенное с помощью оператора присвоения.

CRT>По идее, такое конструирование — это избыточность в языке, достаточно было оставить
CRT>
CRT>A obj(1024);
CRT>

CRT>И эта избыточность запутывает

А такой синтаксис:
int obj = 1024;

не вызывает затруднений?
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: Почему нельзя писать void ctor();
От: CRT  
Дата: 26.04.17 08:17
Оценка:
Здравствуйте, rg45, Вы писали:


R>А такой синтаксис:

R>
R>int obj = 1024;
R>

R>не вызывает затруднений?

это воспринимается как совмещение двух операций в одной строке
int obj;
obj = 1024;

выглядит как такой удобный способ сокращенной записи одной строкой: объявил и тут же присвоил.

Когда человек видит "=" он первым делом, и это естественно, думает что здесь срабатывает оператор присвоения.
Поэтому это не очевидно — то есть непонятно на первый взгляд — в таком синтаксисе, что
A obj=A(1024);

равно
A obj(1024);
Отредактировано 26.04.2017 8:24 CRT . Предыдущая версия . Еще …
Отредактировано 26.04.2017 8:24 CRT . Предыдущая версия .
Отредактировано 26.04.2017 8:21 CRT . Предыдущая версия .
Отредактировано 26.04.2017 8:20 CRT . Предыдущая версия .
Re[10]: Почему нельзя писать void ctor();
От: rg45 СССР  
Дата: 26.04.17 08:28
Оценка:
Здравствуйте, CRT, Вы писали:

CRT>Здравствуйте, rg45, Вы писали:


R>>А такой синтаксис:

R>>
R>>int obj = 1024;
R>>

R>>не вызывает затруднений?

CRT>а это не выглядит как вызов метода конструктора.


A если так?
int obj = int(1024);


CRT>это воспринимается как совмещение двух операций

CRT>
CRT>int obj;
CRT>obj = 1024;
CRT>


Что тебе мешает и в случае с пользовательским типом думать об этом как о совмещении двух операций?
A obj;
obj = A(1024);


Ты же не упускай из виду, что синтаксис спользования типов, определенных пользователем, целенаправленно делали похожим на синтаксис использования встроенных типов — чтобы максимально способствовать обобщенному программированию. Это позволяет, например, совершенно безболезненно для пользователя использовать в качестве итератора вектора как специальные классы, содержащие отладочную информацию, так и сырые указатели.
--
Справедливость выше закона. А человечность выше справедливости.
Re[11]: Почему нельзя писать void ctor();
От: CRT  
Дата: 26.04.17 08:47
Оценка:
Здравствуйте, rg45, Вы писали:


CRT>>а это не выглядит как вызов метода конструктора.


R>A если так?

R>
R>int obj = int(1024);
R>



Так — выглядит. Выглядит как вызов конструктора а потом присвоение. Только так со встроенными типами очень мало кто пишет. Зачем для инта вызывать конструктор? Да многие даже не знают что у int он как бы есть.

CRT>>это воспринимается как совмещение двух операций

CRT>>
CRT>>int obj;
CRT>>obj = 1024;
CRT>>


R>Что тебе мешает и в случае с пользовательским типом думать об этом как о совмещении двух операций?


Ничего не мешает. В том-то и проблема. Многие так и думают поначалу. А потом удивляются, почему оператор присвоения, который они определили для своего класса, не срабатывает в записи
A obj=A(1024)
Отредактировано 26.04.2017 9:07 CRT . Предыдущая версия . Еще …
Отредактировано 26.04.2017 8:54 CRT . Предыдущая версия .
Re[10]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 26.04.17 19:55
Оценка:
Здравствуйте, CRT, Вы писали:

CRT>Поэтому это не очевидно — то есть непонятно на первый взгляд — в таком синтаксисе, что

CRT>
CRT>A obj=A(1024);
CRT>

CRT>равно
CRT>
CRT>A obj(1024);
CRT>


А они и не равны...

Попробуй скомпилировать...
class A {
    A(const A&);
public:
    int Data;
    A(int i = 0) : Data(i) {}
};

A obj = A(1024);

По С++ компилятор в такой штуке имеет право выбрасывать конструктор копии, так же, как и при RVO/NRVO, но не имеет права не проверять его доступность...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Почему нельзя писать void ctor();
От: CRT  
Дата: 27.04.17 07:42
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, CRT, Вы писали:


CRT>>Поэтому это не очевидно — то есть непонятно на первый взгляд — в таком синтаксисе, что

CRT>>
CRT>>A obj=A(1024);
CRT>>

CRT>>равно
CRT>>
CRT>>A obj(1024);
CRT>>


E>А они и не равны...


E>Попробуй скомпилировать...
E>class A {
E>    A(const A&);
E>public:
E>    int Data;
E>    A(int i = 0) : Data(i) {}
E>};

E>A obj = A(1024);

E>По С++ компилятор в такой штуке имеет право выбрасывать конструктор копии, так же, как и при RVO/NRVO, но не имеет права не проверять его доступность...

А зачем мне компилировать такое? И что оно вообще значит? То есть класс в котором объявлен но не определен конструктор копирования.
Но я попробовал скомпилировать. Ничего особого не произошло. Вызвался конструктор A(int). То есть я вижу что код A obj = A(1024); отработал так же как A obj(1024). Значит, делают вывод — равны.

Поправочка: в том что я попробовал A(const A&) был после паблик, а если его в private засунуть то не компилируется. Нужен конструктор копирования. Но с практической точки зрения. С точки зрения того, что делает программа, когда выполняется, все равно получается что A obj = A(1024) равно A obj(1024).
Отредактировано 27.04.2017 7:47 CRT . Предыдущая версия . Еще …
Отредактировано 27.04.2017 7:45 CRT . Предыдущая версия .
Re[11]: Почему нельзя писать void ctor();
От: CRT  
Дата: 27.04.17 07:57
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, CRT, Вы писали:


CRT>>Поэтому это не очевидно — то есть непонятно на первый взгляд — в таком синтаксисе, что

CRT>>
CRT>>A obj=A(1024);
CRT>>

CRT>>равно
CRT>>
CRT>>A obj(1024);
CRT>>


E>А они и не равны...


E>Попробуй скомпилировать...
E>class A {
E>    A(const A&);
E>public:
E>    int Data;
E>    A(int i = 0) : Data(i) {}
E>};

E>A obj = A(1024);

E>По С++ компилятор в такой штуке имеет право выбрасывать конструктор копии, так же, как и при RVO/NRVO, но не имеет права не проверять его доступность...

Действительно A obj = A(1024) требует наличия конструктора копирования, однако с точки зрения того что делает программа, что A obj= A(10) что A obj(10) — получается одно и то же.
Re[3]: Почему нельзя писать void ctor();
От: N. I.  
Дата: 27.04.17 17:03
Оценка:
Максим Рогожин:

МР>Мужики, еще немного занудства) Учитывая все сказанное, а почему тогда разрешен следующий синтаксис?


МР>
A obj = A(1024);

МР>Глядя на эту запись можно подумать, что здесь конструктор именно зовется напрямую и возвращает значение

Начнём с того, что A(1024) — это вовсе не обычный function call, а явное преобразование типа в функциональной нотации, которое в данном случае эквивалентно static_cast<A>(1024) и выполняется посредством конструктора. Существует масса других случаев, когда преобразование вида T(x) не использует какие-либо конструкторы. Например, short(1024) преобразует значение типа int к short без применения конструкторов. Добавив в класс A конструктор A(int), ты определил пользовательское преобразование из int в A, что и даёт тебе возможность использовать выражение вроде A(1024). Явные преобразования типов и обычные вызовы функций — это разные вещи, регламентируемые разными правилами, и то, что их синтаксис похож, не должно создавать излишних иллюзий насчёт их похожести во всём.
Re[10]: Почему нельзя писать void ctor();
От: N. I.  
Дата: 27.04.17 17:10
Оценка: 2 (1) +1
CRT:

CRT>Поэтому это не очевидно — то есть непонятно на первый взгляд — в таком синтаксисе, что

CRT>
A obj=A(1024);

CRT>равно
CRT>
A obj(1024);

C++ — это вообще не тот язык, где всё становится очевидно после пары дней беглого знакомства с его правилами. Тут пока досконально не узучишь детали, не поймёшь, как оно работает.

Нечто вроде

T x = T(arg);

не является какой-то специальной конструкцией языка, это всего лишь частный случай инициализации вида

T x = a;

где в качестве a выступает некое выражение T(arg).

В отличие от общей direct-initialization

T x(a);

copy-initialization

T x = a;

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

std::string const s = "text";
std::vector<int> v(42);

Здесь литерал "text" и объект s по сути представляют одну и ту же сущность — строку text. Различия состоят лишь в способе хранения этой строки и наборе доступных операций над ней.

v непосредственно после своей инициализации хранит последовательность из 42-х нулей, и эту последовательность из 42-х нулей довольно трудно назвать близкой по смыслу к самому числу 42. Конструктор vector-а, где мы указываем размер, объявлен как explicit, что как раз запрещает использование

std::vector<int> v = 42;

поэтому здесь мы вынуждены использовать direct-initialization, тем самым указывая на потенциальную возможность большого различия между смыслом того, что мы иницилизируем, и смыслом того, чем мы инициализируем. Своеобразная универсальность direct-initialization не делает её всегда лучше, чем copy-initialization, точно так же, как универсальность (T)arg не делает данный вид преобразования всегда лучше, чем более ограниченный static_cast<T>(arg).

Я не вижу особого смысла в использовании

T x = T(a);

вместо

T x(a);

где T — это классовый тип. Насколько я вижу, по правилам С++17 эти два варианта полностью идентичны. Но я и не вижу каких-либо причин запрещать первый вариант на уровне языка. Как минимум, нечто подобное вполне могло бы получиться в виде частного случая при инстанцировании какого-нибудь шаблона или раскрытии какого-нибудь макроса, и было бы странно если б оно внезапно перестало собираться.
Отредактировано 27.04.2017 17:30 N. I. . Предыдущая версия .
Re[4]: Почему нельзя писать void ctor();
От: CRT  
Дата: 27.04.17 20:17
Оценка:
Здравствуйте, N. I., Вы писали:

NI>Максим Рогожин:


МР>>Мужики, еще немного занудства) Учитывая все сказанное, а почему тогда разрешен следующий синтаксис?


МР>>
NI>A obj = A(1024);
NI>

МР>>Глядя на эту запись можно подумать, что здесь конструктор именно зовется напрямую и возвращает значение

NI>Начнём с того, что A(1024) — это вовсе не обычный function call, а явное преобразование типа в функциональной нотации, которое в данном случае эквивалентно static_cast<A>(1024) и выполняется посредством конструктора. Существует масса других случаев, когда преобразование вида T(x) не использует какие-либо конструкторы. Например, short(1024) преобразует значение типа int к short без применения конструкторов. Добавив в класс A конструктор A(int), ты определил пользовательское преобразование из int в A, что и даёт тебе возможность использовать выражение вроде A(1024). Явные преобразования типов и обычные вызовы функций — это разные вещи, регламентируемые разными правилами, и то, что их синтаксис похож, не должно создавать излишних иллюзий насчёт их похожести во всём.


Хорошо, A(1024) это преобразование типа.
Но вот это
A obj = A(1024,"ъъъ");

уже явно не выглядит как преобразование типа, а именно как вызов конструктора напрямую , который возвращает значение.
А по мне так конструктор с одним параметром — это частный случай конструктора с N параметрами.
Re[5]: Почему нельзя писать void ctor();
От: N. I.  
Дата: 27.04.17 22:11
Оценка:
CRT:

CRT>Хорошо, A(1024) это преобразование типа.

CRT>Но вот это
CRT>
A obj = A(1024,"ъъъ");

CRT>уже явно не выглядит как преобразование типа

Однако, формально это тоже относится к преобразованию типа — Explicit type conversion (functional notation) — от списка из нескольких выражений.

CRT>а именно как вызов конструктора напрямую , который возвращает значение.


Конструктор только инициализирует объект, но выделением того участка памяти, которая становится объектом (и размер которой мы можем узнать с помощью sizeof), он не занимается. Деструктор объекта он обычно тоже не вызывает. Как и определение переменной A a(1024,"ъъъ"); , выражение A(1024,"ъъъ") приводит не только к вызову конструктора, но ещё и резервированию памяти под создаваемый объект, а также к вызову деструктора в какой-то момент, а стало быть, это всё-таки более высокоуровневая штука, чем некий простой вызов конструктора. Если нужно выражение, которое по сути не делает ничего, кроме вызова конструктора (с предшествующей инициализацией его параметров), то для этого надо использовать что-то вроде ::new((void *)pointer) A(1024,"ъъъ"), где pointer указывает на участок памяти, который мы собираемся отвести под объект. Хотя формально тут всё же есть ещё вызов функции operator new, эта версия operator new реально ничего не делает, а потому фактическая функциональность такого выражения сводится к вызову конструктора.

CRT>А по мне так конструктор с одним параметром — это частный случай конструктора с N параметрами.


А как тебе вот такой пример?

#include <iostream>

struct A
{
    A(A &&) = delete;
    int n;
};

A f()
{
    return A{1024};
}

int main()
{
    A obj = A(f());
    std::cout << obj.n << std::endl;
}

По правилам C++17 здесь нет ни одного вызова конструктора A (собственно, такой A даже не имеет ни одного конструктора, который было бы допустимо вызывать), и, тем не менее, эта программа вполне рабочая.
Отредактировано 27.04.2017 22:21 N. I. . Предыдущая версия .
Re[6]: Почему нельзя писать void ctor();
От: uzhas Ниоткуда  
Дата: 28.04.17 09:51
Оценка:
Здравствуйте, N. I., Вы писали:

NI>А как тебе вот такой пример?

...
NI>По правилам C++17 здесь нет ни одного вызова конструктора A (собственно, такой A даже не имеет ни одного конструктора, который было бы допустимо вызывать), и, тем не менее, эта программа вполне рабочая.

а можно пояснить, почему нет вызова конструктора?
вот тут видно, что деструктор вызывается: https://wandbox.org/permlink/UB1kdA5fS0h2Mo5Q
значит, был вызов и конструктора?
Re[7]: Почему нельзя писать void ctor();
От: night beast СССР  
Дата: 28.04.17 09:56
Оценка:
Здравствуйте, uzhas, Вы писали:

U>а можно пояснить, почему нет вызова конструктора?

U>вот тут видно, что деструктор вызывается: https://wandbox.org/permlink/UB1kdA5fS0h2Mo5Q
U>значит, был вызов и конструктора?

является ли aggregate initialization вызовом конструктора?
Re[8]: Почему нельзя писать void ctor();
От: uzhas Ниоткуда  
Дата: 28.04.17 10:11
Оценка:
Здравствуйте, night beast, Вы писали:

NB>является ли aggregate initialization вызовом конструктора?


вопрос на миллион!
Re[12]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 28.04.17 20:35
Оценка:
Здравствуйте, CRT, Вы писали:

E>>Попробуй скомпилировать...
E>>class A {
E>>    A(const A&);
E>>public:
E>>    int Data;
E>>    A(int i = 0) : Data(i) {}
E>>};

E>>A obj = A(1024);

CRT>А зачем мне компилировать такое? И что оно вообще значит?
Что конструктор копии A является private...

CRT>Но я попробовал скомпилировать. Ничего особого не произошло. Вызвался конструктор A(int). То есть я вижу что код A obj = A(1024); отработал так же как A obj(1024). Значит, делают вывод — равны.

C private конструктором копии?.. А каким компилятором?

CRT>Поправочка: в том что я попробовал A(const A&) был после паблик, а если его в private засунуть то не компилируется.

Так в этом и состоит смысл жеж

Смотри, что я утверждал:
E>>По С++ компилятор в такой штуке имеет право выбрасывать конструктор копии, так же, как и при RVO/NRVO, но не имеет права не проверять его доступность...

Дальше, если хочешь разобраться, то разбираешься. Я пытался помочь в этом, но можешь просто прочитать стандарт.
Если не хочешь, то и обсуждать нечего...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Почему нельзя писать void ctor();
От: CRT  
Дата: 28.04.17 20:39
Оценка: +1
Здравствуйте, Erop, Вы писали:


CRT>>Поправочка: в том что я попробовал A(const A&) был после паблик, а если его в private засунуть то не компилируется.

E>Так в этом и состоит смысл жеж

да я понял что в этом смысл. Просто сразу не заметил что A(const A&) закрыт.
Re[12]: Почему нельзя писать void ctor();
От: Erop Россия  
Дата: 28.04.17 20:40
Оценка:
Здравствуйте, CRT, Вы писали:

E>>По С++ компилятор в такой штуке имеет право выбрасывать конструктор копии, так же, как и при RVO/NRVO, но не имеет права не проверять его доступность...


CRT>Действительно A obj = A(1024) требует наличия конструктора копирования, однако с точки зрения того что делает программа, что A obj= A(10) что A obj(10) — получается одно и то же.


Ну так это же оптимизация просто.

В этом смысле и программы
std::cout << 2+2;
и
std::cout << 4;
делают одно и тоже одинаковым кодом, но логически написано разное.

В этом смысле
A a = A(1234);
не особо понятно чем отличается.
A(1234) -- это выражение, типа A.
Компилятор может такую конструкцию оптимизировать до
A a(1234);
это прямо разрешено в стандарте.
В чём ты тут вообще усматриваешь принципиальную разницу с
std::cout << 4;
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Почему нельзя писать void ctor();
От: N. I.  
Дата: 28.04.17 21:37
Оценка:
uzhas:

U>а можно пояснить, почему нет вызова конструктора?


A{1024} выполняет aggregate initialization, которая инициализирует объект типа A без привлечения конструкторов. По новым правилам результат A{1024}, return object функции f, результат преобразования A(f()) и obj — это один и тот же объект; никаких дополнительных объектов типа A нигде не создаётся.

Отдельного упоминания заслуживает вот такой пример:

#include <iostream>

void *ptr;

struct X
{
    X() { ptr = this; }
};

struct A
{
    A(A &&) = delete;
    X x;

private:
    A(A &) = default;
};

A f()
{
    return A{};
}

int main()
{
    A obj = A(f());
    std::cout << (&obj == ptr) << std::endl;
    std::cout << &obj << std::endl;
    std::cout << ptr << std::endl;
}

Здесь наличие конструктора A(A &) позволяет делать копию объекта при возврате из функции f (то, что конструктор приватный и не может принимать rvalue типа A, в данном случае роли не играет), отчего равенство (&obj == ptr) может не соблюдаться. Хотя gcc 8 пока что имеет наглость создавать копию и при полном отсутствии non-deleted copy/move-конструкторов, что, насколько я вижу, является нарушением правил.

U>вот тут видно, что деструктор вызывается: https://wandbox.org/permlink/UB1kdA5fS0h2Mo5Q

U>значит, был вызов и конструктора?

Объект классового типа может быть инициализирован без использования конструктора, это никак не мешает ему быть уничтоженным с помощью деструктора.
Отредактировано 28.04.2017 21:41 N. I. . Предыдущая версия .
Re[7]: Почему нельзя писать void ctor();
От: Максим Рогожин Россия  
Дата: 17.10.17 16:56
Оценка:
Здравствуйте, rg45, Вы писали:

R>для создания rvalue объекта во временной области памяти:

const auto& obj = A(1024);
aFunction(A(1024) + A(42));


А можно уточнить где будут созданы объекты A(1024) и A(42)? Что за временная область памяти? Это понятие есть в стандарте? Или то где будут
созданы эти два объекта это implementation details?
Re: Почему нельзя писать void ctor();
От: Pzz Россия https://github.com/alexpevzner
Дата: 17.10.17 17:26
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?


Нет, просто договоренность такая, что конструктор не имеет явно указанного возвращаемого типа. Конструктор в любом случае — особая функция, и компилятор понимает, как для него организовывать стек и прочий пролог.
Re[3]: Почему нельзя писать void ctor();
От: Mr.Delphist  
Дата: 18.10.17 11:54
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Это понятно. Но я думал, что void как раз и означает что функция не возвращает СОВСЕМ НИКАКОГО значения. Это не так?


Нет, не так. void — это специальный тип-пустышка, тип-джокер.

void foo(void *p)
{
    int x = (int)p; // трактуем указатель p как обычное целое число
    int y = *(int*)p; // трактуем указатель p как указатель на целое число и сразу разыменовываем
    int z = ******************************************************(int******************************************************)p; // это компилируется, я проверял
    void *wut = (void*)( p ? (int)p ^ (int)p : (int)p % (int)p); // ну, мне пора :)
}
Re[2]: Почему нельзя писать void ctor();
От: kov_serg Россия  
Дата: 18.10.17 12:26
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, Максим Рогожин, Вы писали:


МР>>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?


Pzz>Нет, просто договоренность такая, что конструктор не имеет явно указанного возвращаемого типа. Конструктор в любом случае — особая функция, и компилятор понимает, как для него организовывать стек и прочий пролог.


А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз.
И почему private выбрали по умолчанию вместо public. Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl
Типа такого

// header

class A : B {
   ctor();
   dtor();
   nonvirtual void fn();
   void gn()=0; 
};

// impl

implement class A {
  ctor() { ... }
  dtor() { ... }
  void fn() { parent::member(); }
}

А указатели на методы класса всегда вызывали смутные эмоции.
Re[3]: Почему нельзя писать void ctor();
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.10.17 12:58
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз.


Ну например за тем, чтобы не вводить еще одного ключевого словак, которое, тем самым, станет недоступным в качестве идентификатора.

_>И почему private выбрали по умолчанию вместо public.


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

_>Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl


Это я не слишком-то понял.

_>А указатели на методы класса всегда вызывали смутные эмоции.


А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
Re[4]: Почему нельзя писать void ctor();
От: kov_serg Россия  
Дата: 18.10.17 13:14
Оценка:
Здравствуйте, Pzz, Вы писали:

_>>Не говоря уже об отсутствие аккумулятора и возрате последнего значения как в perl

Pzz>Это я не слишком-то понял.
int min(int x,int y) { if (x<y) x; else y; }
int x={ if (a<0) 0; else a; };

min(z[0],z[1]); min(_,z[2]); min(_,z[3]);
int last_result=_;


_>>А указатели на методы класса всегда вызывали смутные эмоции.

Pzz>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
да стрелку могли бы приспособить для правого присвоения
10+2*5 -> a
Re[5]: Почему нельзя писать void ctor();
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.10.17 13:19
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>
_>int min(int x,int y) { if (x<y) x; else y; }
_>int x={ if (a<0) 0; else a; };

_>min(z[0],z[1]); min(_,z[2]); min(_,z[3]);
_>int last_result=_;

_>


У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок. Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?

Pzz>>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...

_>да стрелку могли бы приспособить для правого присвоения
_>10+2*5 -> a

Угу. А еще надо присваивание вверх и вниз:

int           a, b;
              ^
b = 10 + (2*5)|;


Промежуточное значение заносим в переменную a, а окончательный результат — в переменную b.
Re[4]: Почему нельзя писать void ctor();
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.10.17 13:26
Оценка:
Здравствуйте, rg45, Вы писали:

R>Эти две записи похожи лишь формально. Только в первом случае это является не возвращением значения, а прямым конструированием объекта в правой части инициализатора. Это то же самое выражение, которое используется в операторе return в функции createObject:


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

А чтобы жизнь им окончательно не казалось медом, пространство имен функций и пространство имен типов — это разные пространства. Т.е., в принципе, имя функции может совпадать с именем класса, и поэтому надо сначала пытаться найти имя среди имен функций, а потом — среди имен типов.
Re[4]: Почему нельзя писать void ctor();
От: Pzz Россия https://github.com/alexpevzner
Дата: 18.10.17 13:28
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Для чего запрещать конструктору возвращать даже void, но при этом разрешать следующий синтаксис?


МР>
МР>A obj = A(1024);
МР>


Чтобы можно было сконструировать временный объект, и не засосывать его явно в какую-либо переменную.
Re[6]: Почему нельзя писать void ctor();
От: kov_serg Россия  
Дата: 18.10.17 13:36
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, kov_serg, Вы писали:


_>>
_>>int min(int x,int y) { if (x<y) x; else y; }
_>>int x={ if (a<0) 0; else a; };

_>>min(z[0],z[1]); min(_,z[2]); min(_,z[3]);
_>>int last_result=_;

_>>


Pzz>У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок.

Pzz>Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?
return это выход из функции. А тут последнее значение можно передавать в функцию по умолчанию
(неявно как this) при этом жесткая типизация и шаблоны позволили бы сделать очень интересные вещи.

Pzz>>>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные.

Pzz>>>Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...
_>>да стрелку могли бы приспособить для правого присвоения
_>>10+2*5 -> a

Pzz>Угу. А еще надо присваивание вверх и вниз:


Pzz>
Pzz>int           a, b;
Pzz>              ^
Pzz>b = 10 + (2*5)|;
Pzz>

Pzz>Промежуточное значение заносим в переменную a, а окончательный результат — в переменную b.
Вы чертов гений! Надо вообще сделать 10+2*5->(goto +10,-2) или 10+2*5->(looks like z[] or has prefix result_) или 0->(all unsigned)
Вообще rightward operator иногда очень даже удобен
https://stat.ethz.ch/R-manual/R-devel/library/base/html/assignOps.html

ps: Напомню: "что настоящий ученый может писать фортраном на любом языке"
Re[4]: Почему нельзя писать void ctor();
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.10.17 07:26
Оценка:
Здравствуйте, Pzz, Вы писали:

_>>А меня всегда удивляло почему нельзя было для конструктора и деструктора зарезервировать какие-нибудь имена, а не писать имя класса каждый раз.

Pzz>Ну например за тем, чтобы не вводить еще одного ключевого словак, которое, тем самым, станет недоступным в качестве идентификатора.

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

Представим себе язык, где $ — префикс "это всегда идентификатор", а @ — "это всегда ключевое слово"; без префикса — есть список стандартно понимаемых ключевых слов (и в некоторых контекстах может расширяться). Допустить даже варианты типа $"a b c", если кому-то нужны такие дикие идентификаторы.
Тогда можем получать и любые идентификаторы, и возможность пробных расширений языка на новые использования. Захотел какое-нибудь @foomode — добавил без конфликта; устоялось — объявил, что через 3 года будет пониматься без '@' — у всех есть время переключиться.

На самом деле тот же C# частично начал двигаться в эту сторону за счёт рекомендации стиля использовать заглавные для любого внешнего идентификатора — зона конфликта резко сокращается и, что главное, обычно не выходит за пределы внутренностей модуля. Go это формализовал до конца — там заглавная обязательна для экспорта, ключевые слова только со строчной, и они не опасаются за устойчивость любых пользовательских API против этого расширения.

А писать init вместо CVeryLongAndTerribleApiBeastFactory, по-моему, достаточно удобно

_>>И почему private выбрали по умолчанию вместо public.


Pzz>Это как-раз правильно. Если бы все члены классов были по умолчанию public, то у индусов в программах вообще все члены были бы всегда public, и никакого ограничения видимости никто бы не использовал.


Pzz>А меня, после знакомства с Go, стало бесить, что в Си операторы . и -> разные. Казалось бы, компилятор и так знает, что стоит слева, структура или указатель на структуру, и хватили бы одного оператора на оба случая...


Почему Go, меня и после Python и Java это удивляет хорошо хоть ошибки обычно тривиальные.
The God is real, unless declared integer.
Re[6]: Почему нельзя писать void ctor();
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.10.17 07:29
Оценка:
Здравствуйте, Pzz, Вы писали:

_>>
_>>int min(int x,int y) { if (x<y) x; else y; }
_>>int x={ if (a<0) 0; else a; };

_>>min(z[0],z[1]); min(_,z[2]); min(_,z[3]);
_>>int last_result=_;

_>>


Pzz>У gcc есть такое расширение. Но в принципе, эта конструкция — источник глупых ошибок. Откуда компилятору знать, я действительно имел ввиду последнее значение в блоке, или просто забыл сказать return где-то в середине?


А это надо решать точно так же, как с проблемой if (a = b): требовать явной пометки таких случаев. Вводим новое слово — например, take.

if (a == b) — нет проблем.
if (take a = b) — нет проблем, при чтении чётко понятно, что тут ещё и присвоение.
if (a = b) — не компилируется, присвоение без take не имеет понятия результата.
a = take b = take c = 0 — побочный эффект, чуть больше слов. Но такие конструкции сейчас очень редки, так что можно потерпеть.
a = take if (x > 0) x; else -x; — явно берём результат ifʼа, компилятор знает, что блоки внутри if должны выдавать значение.

Pzz>Угу. А еще надо присваивание вверх и вниз:


The God is real, unless declared integer.
Re[2]: Почему нельзя писать void ctor();
От: _hum_ Беларусь  
Дата: 19.10.17 20:55
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Максим Рогожин, Вы писали:


МР>>Почему нельзя писать так


МР>>class A {

МР>>public:
МР>> void A() {}
МР>>};
МР>>?

N>Страуструп писал, что это для подчёркивания того факта, что конструктор никогда не зовётся напрямую.



МР>>Отличается ли из-за этого низкоуровневая организация вызова этой функции (организация стека, пролог, эпилог)?


N>Вот принятое в Unix ABI, например, знает


  code
N>
N>  <ctor-dtor-name> ::= C1    # complete object constructor
N>           ::= C2    # base object constructor
N>           ::= C3    # complete object allocating constructor
N>           ::= D0    # deleting destructor
N>           ::= D1    # complete object destructor
N>           ::= D2    # base object destructor
N>


N>В этом случае тот конструктор, что с C3, аллоцирует память и возвращает адрес объекта, а те, что C1 и C2, получают первым скрытым параметром адрес объекта и ничего не возвращают.


N>Больше отличий нет, остальное идентично обычной функции.


N>Для MSVC правил не знаю, могут быть хитрости.



так а, действительно, что тогда мешает официально изменить семантику конструктора на вариант наподобие "создает объект класса и инициализирует его, после чего возращает ссылку на этот объект"?
(токо недавно обсуждали, что, например, в таком случае такое новое понятие, как User-defined deduction guides, можно было бы тогда свести к декларации шаблона такого конструктора. это я к тому, что, возможно, это могло бы помочь с введением новых нужных понятий через уже старые.)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.