С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
1

Возможна ли инициализация в инициализации?

23.08.2016, 12:38. Показов 1603. Ответов 24
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Изучая новый стандарт, заинтересовался: а можно ли как-то сделать массив указателей, например, на тип int, инициализируя ссылочные переменные, на которые указывали бы указатели, в одном выражении? Как-то так:
C++
1
int* pArr[] = {&(int a = 5), &(int b = 8)}
Или это слишком мерзкое извращение для компактности?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.08.2016, 12:38
Ответы с готовыми решениями:

Инициализация (ООП, списки инициализации)
Доброго времени суток, хотелось бы узнать, как происходит процесс инициализации полей класса при...

Инициализация в теле конструктора или в списке инициализации.
Здрасте. class random1 { public: random(): a(5) {} private: int a; };

Инициализация не агрегированных данных списка инициализации не допускается
Подскажите как исправить эту ошибку #include "stdafx.h" #include "iostream" using namespace...

Инициализация в теле конструктора или в списке инициализации, есть ли разница в сгенерированном коде?
Инициализация в теле конструктора или в списке инициализации - большая ли разница в сгенерированном...

24
829 / 253 / 34
Регистрация: 27.07.2016
Сообщений: 497
Записей в блоге: 1
23.08.2016, 12:48 2
Lyosha12, даже если бы у Вас получилось, это были бы указатели на временные объекты, которые удалились бы следом и указатели в Вашем массиве бы протухли

Добавлено через 3 минуты
Но реализовать это всё можно, например, так:
C++
1
2
3
4
5
6
7
8
9
10
11
template<typename T>
T *getAddress(T &&arg)
{
    return std::addressof(arg);
}
 
 
int main()
{
    int * arr[] = {getAddress(int(10)), getAddress(int(10))};
}
собственно и получаем "протухшие" указатели.
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 13:12  [ТС] 3
С временными объектами ещё не знакомился, но полагаю, что, если они не закреплены за какой-то ссылкой, то они удаляются, как только ссылка выходит из области видимости.

В приведенном примере Вы дали жизнь временному объекту, инициализировав ссылку адресом rvalue. Верно? И с объектом ничего не случится, пока не будет уничтожена эта ссылка? Или в этом и отличие: rvalue-ссылки именно временные объекты и ссылки на них могут устареть, а обычная инициализация переменной как-то бронирует адрес временного объекта, созданного через int()? (Вопрос: как? )

Но тема о другом. Я не хотел иметь дело с временными объектами. В списке инициализации инициализировались бы переменные типа int, а уже на них ссылались бы указатели в массиве.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 13:14 4
Лучший ответ Сообщение было отмечено Lyosha12 как решение

Решение

Цитата Сообщение от Lyosha12 Посмотреть сообщение
int* pArr[] = {&(int a = 5), &(int b = 8)}
Внимание, смертельный номер (дома не повторять):
C++
1
2
3
4
    int * arr[] =
    {
        new(alloca(sizeof(int))) int(5), new(alloca(sizeof(int))) int(8)
    };
Указатели не протухнут до выхода из scope. Правда функция alloca не стандартная, но присутствует почти везде.

PS. Естественно все вышеописанное - шутка, не надо такое писать.
3
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 13:51  [ТС] 5
malloc выделяет место в куче, а alloca - в стеке. Но как можно (и зачем) выделять место в стеке? На лекциях нам говорили, что массив, размещённый на стеке, должен иметь строго определённый размер, так как память выделяется при компиляции и после неё мы над памятью в стеке не властны.

И почему Вы не рекомендуете заниматься размещением-инициализацией памяти, если в вики прямо говорится об практическом использовании?

Существует особая форма оператора new, называемая Placement new. Данный оператор не выделяет память, а получает своим аргументом адрес на уже выделенную каким-либо образом память (например, на стеке или через malloc()). Происходит размещение (инициализация) объекта путём вызова конструктора, и объект создается в памяти по указанному адресу. Часто такой метод применяют, когда у класса нет конструктора по умолчанию и при этом нужно создать массив объектов.
Добавлено через 5 минут
Получается, что для временных объектов память отводится строго для нужд использования их в операциях, конкретно, в регистрах процессора? Потому-то они и временные? А зарезервировав память, которую отдаст ОС из RAM, мы получим уже долгоживущий объект. Верно?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 14:00 6
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Но как можно (и зачем) выделять место в стеке?
Так заведено, что объекты автоматических переменных размещаются в стеке.

Цитата Сообщение от Lyosha12 Посмотреть сообщение
На лекциях нам говорили, что массив, размещённый на стеке, должен иметь строго определённый размер, так как память выделяется при компиляции и после неё мы над памятью в стеке не властны.
Причем здесь массив?
Массив тут один, и он был и в изначальном посте. Он также размещен в стеке. И да, он имеет строго определенный размер, заданный на этапе компиляции - 2. Никаких разночтений с лекцией пока что
Что касается alloca, то она тоже выделяет память в стеке, подобно тому, как поступает компилятор. Более того, по ссылке выше написано, что в GNU реализации - это не функция, а специальная инструкция компилятора, которая резервирует место в стеке. "Резервирование", обычно заключается в смещении специального регистра - указателя стека - на заданную величину.

Цитата Сообщение от Lyosha12 Посмотреть сообщение
И почему Вы не рекомендуете заниматься размещением-инициализацией памяти, если в вики прямо говорится об практическом использовании?
Я говорил не про размещающий new как таковой. А про комбинацию alloca + placement new, и, в частности, идею твоего стартового поста. Не нужно экономить на строчках.
Тем не менее, мой пример на данный момент является наиболее близким решением поставленной тобой задачи (за исключением синтаксиса). Т.е. пример выше - это почти полный эквивалент вот такого кода:
C++
1
2
int a_ = 5, b_ = 8;
int * arr[] = { &a_, &b_ };
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 14:25  [ТС] 7
Цитата Сообщение от DrOffset Посмотреть сообщение
Что касается alloca, то она тоже выделяет память в стеке, подобно тому, как поступает компилятор. Более того, по ссылке выше написано, что в GNU реализации - это не функция, а специальная инструкция компилятора, которая резервирует место в стеке. "Резервирование", обычно заключается в смещении специального регистра - указателя стека - на заданную величину.
То есть, память всё-таки выделяется при компиляции... И такую функцию, наверно, создавали для типов, размер которых отличен от стандартных (верно?).
Цитата Сообщение от DrOffset Посмотреть сообщение
Тем не менее, мой пример на данный момент является наиболее близким решением поставленной тобой задачи (за исключением синтаксиса).
Но ведь то же самое, на мой взгляд, делает и это:
C++
1
2
3
int* arr[] = {new int(5), new int(8)};
 
    cout << *arr[1];
Только в данном, как и в Вашем, примере я не смогу обратиться к объектам по ссылке, так как её адрес переходит сразу во владение указателям. В чём разница?

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

Добавлено через 3 минуты
В принципе, инициализация в инициализации, как Вы показали, возможна, ведь для инициализации массива указателей требуются адреса, которые возвращает оператор new. И, как я вижу из примеров, объявить и ссылку на объект, и взять её адрес, и присвоить значению указателя, используя всего одно выражение, нельзя. (Не учитывая извращения с макросами)

Добавлено через 6 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
Причем здесь массив?
Массив тут один, и он был и в изначальном посте. Он также размещен в стеке.
Перегнул палку намёков. Имел ввиду, что Вы выделяете так память в стеке уже во время выполнения.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 14:33 8
Цитата Сообщение от Lyosha12 Посмотреть сообщение
И такую функцию, наверно, создавали для типов, размер которых отличен от стандартных (верно?).
Не совсем. Функцию создавали, чтобы иметь возможность запрашивать со стека произвольный (в границах стека, конечно) кусок памяти.
Указатель стека мы и на этапе исполнения можем изменить, например ассемблерной вставкой. Просто эта функция делает это заведомо правильно.

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

Цитата Сообщение от Lyosha12 Посмотреть сообщение
Да и не знать особенностей синтаксиса - тоже как-то не хорошо.
У тебя проблемы в понимании работы памяти. Лучше начать с этого - синтаксис, особенно такой редкоиспользуемый, подождет.

Цитата Сообщение от Lyosha12 Посмотреть сообщение
когда преподаватели старой закалки требуют печатать все программы.
Это уже вопрос экономии бумаги.

Добавлено через 4 минуты
Цитата Сообщение от Lyosha12 Посмотреть сообщение
И, как я вижу из примеров, объявить и ссылку на объект, и взять её адрес, и присвоить значению указателя, используя всего одно выражение, нельзя.
Начать с того, что ты сильно путаешься в терминах.
Что есть ссылка в твоем понимании здесь?

Цитата Сообщение от Lyosha12 Посмотреть сообщение
Имел ввиду, что Вы выделяете так память в стеке уже во время выполнения.
В данном коде на этапе компиляции. Т.к. используется константа времени компиляции, которую дает sizeof.
Но в целом да, параметром allocа может быть и вычесленное на этапе исполнения число.
1
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 14:39  [ТС] 9
Цитата Сообщение от DrOffset Посмотреть сообщение
У тебя проблемы в понимании работы памяти. Лучше начать с этого - синтаксис, особенно такой редкоиспользуемый, подождет.
Спорить не буду. Читаю материалы по этой теме уже вторую неделю, но всё как-то абстрактно и нет "физики". Узнав про виртуальную память, которую выделяет система особняком от физической, ситуация немного прояснилась. Но вопросы про выход за границы массива и ошибки сегментации остались. "Но это уже совсем другая история".
Цитата Сообщение от DrOffset Посмотреть сообщение
Нет.
Здесь объекты размещаются в куче, следовательно за временем жизни переменных следить должен программист.
Этот пример не аналогичен твоему псевдокоду.
Да, я понял. Вы делаете имитацию стековой переменной, только отрываете от неё имя. Действительно варварство
Цитата Сообщение от DrOffset Посмотреть сообщение
Указатель стека мы и на этапе исполнения можем изменить, например ассемблерной вставкой. Просто эта функция делает это заведомо правильно.
А вот про такую особенность мне не говорили... Ну, опять же, из лекции: "Выделять место на стеке во время выполнения нельзя". Под указателем стека Вы понимаете размер памяти, отведённой ОС процессу?

Добавлено через 2 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Начать с того, что ты сильно путаешься в терминах.
Что есть ссылка в твоем понимании здесь?
Ссылка, как мне объясняли, лишь имя объекта:
C++
1
int a = 7, int& rA = a;
Ну и, соответственно, у меня сложилось впечатление, что ссылка неотделима от стековой памяти (она должна всегда быть, если выделяется память на стеке), выделенной для объекта при компиляции.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 14:51 10
Цитата Сообщение от Lyosha12 Посмотреть сообщение
"Выделять место на стеке во время выполнения нельзя"
Средствами языка С++, да невозможно. В С, начиная со стандарат 99 года - возможно (см. VLA).
Впрочем, зависит как на это смотреть: компилятор только кодирует в двоичный код операции смещения регистра ESP. На этапе исполнения эти операции выполняются процессором и значение регистра меняется. Конкретное значение всегда меняется на этапе исполнения
Поэтому и код с alloca не сильно отличается от того, что происходит по умолчанию. Просто значение для смещения мы подставляем сами.

Цитата Сообщение от Lyosha12 Посмотреть сообщение
Под указателем стека Вы понимаете размер памяти, отведённой ОС процессу?
Под указателем стека в данном случае я понимаю реализацию аппаратного стека в x86-совместимых процессорах, т.е. регистр ESP.

Цитата Сообщение от Lyosha12 Посмотреть сообщение
Ссылка, как мне объясняли, лишь имя объекта:
Ссылка имя объекта - да. Но не всякое имя объекта - ссылка.

Добавлено через 1 минуту
Цитата Сообщение от Lyosha12 Посмотреть сообщение
но всё как-то абстрактно и нет "физики"
Тебе бы ассемблер поизучать.
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 14:55  [ТС] 11
Цитата Сообщение от DrOffset Посмотреть сообщение
Ссылка имя объекта - да. Но не всякое имя объекта - ссылка.
Да. Я имел ввиду, что, инициализируя массив указателей, мы не сможем одновременно и создавать ссылки на объекты, к которым должны привязываться и указатели.

Добавлено через 18 секунд
Цитата Сообщение от DrOffset Посмотреть сообщение
Тебе бы ассемблер поизучать.
Давно горю желанием.
0
2337 / 1825 / 753
Регистрация: 27.07.2012
Сообщений: 5,400
23.08.2016, 15:02 12
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Ну и, соответственно, у меня сложилось впечатление, что ссылка неотделима от стековой памяти (она должна всегда быть, если выделяется память на стеке), выделенной для объекта при компиляции.
Неверное впечатление. Ссылка может быть на любой объект. Иногда ссылка - способ дать имя безымянному объекту:
C++
1
2
int * ptrs[] = { new int(100), new int(500) };
int & obj0 = *(ptrs[0]);
1
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 15:03 13
Цитата Сообщение от Lyosha12 Посмотреть сообщение
инициализируя массив указателей, мы не сможем одновременно и создавать ссылки на объекты, к которым должны привязываться и указатели.
Ты ушел в частности. Все же проще гораздо:
Объявлять переменные (в том числе ссылки) в принципе нельзя в списке иницилизации. Этого нам синтаксис не позволит.
Мы можем попытаться создать объект (как во втором посте), но он будет жить до конца выражения, а потом помрет, оставив висячий указатель. Или можем попытаться зарезервировать память внешним инструментом, чтобы проинициализировать в ней нужный нам объект.
В итоге во всей этой цепочке термин "ссылка" вообще лишний. Ты, употребляя его, только запутываешь себя.
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 15:16  [ТС] 14
Цитата Сообщение от DrOffset Посмотреть сообщение
В итоге во всей этой цепочке термин "ссылка" вообще лишний. Ты, употребляя его, только запутываешь себя.
Я употребил термин "ссылка", так как изначально хотел работать с объектами, адреса которых были бы неотделимы от имении, за которым они закреплены (ссылкой), а так же массивом указателей на такие именованные адреса, который я бы удобно передал в функцию.

Если Вы имеете в виду, что ссылка и адрес - это синонимы, то да, я, наверно, употребил термин некорректно, так как изначально представлял её себе "переменной типа указатель, при обращении к которой не нужно разыменовывать её, дабы получить содержимое по адресу в ней (или её адресу)".
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 15:21 15
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Я употребил термин "ссылка", так как изначально хотел работать с объектами, адреса которых были бы неотделимы от имении, за которым они закреплены (ссылкой), а так же массивом указателей на такие именованные адреса, который я бы удобно передал в функцию.
Да нет в этом примере ссылок.
Цитата Сообщение от Lyosha12 Посмотреть сообщение
int* pArr[] = {&(int a = 5), &(int b = 8)}
Вообще нет.

Если ты хотел, чтобы и имена объявленных переменных также были доступны ниже по коду, то см. еще раз пост 13. Запись
C++
1
int a = 5;
Называется объявлением переменной. Ссылки тут нет.
Ссылка в С++ - это вот:
C++
1
int & ra = a; // ra - ссылка.
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Если Вы имеете в виду, что ссылка и адрес - это синонимы,
Нет, я это не имею в виду
И это не синонимы
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 15:29  [ТС] 16
Так, теперь я уже точно запутался. Если объявленная переменная - не ссылка, тогда что же это, если мы получаем значение этой переменной точно так же, как получаем значение по ссылке на эту переменную?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 15:36 17
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Если объявленная переменная - не ссылка, тогда что же это, если мы получаем значение этой переменной точно так же, как получаем значение по ссылке на эту переменную?
Ссылка - это псевдоним переменной (в высокоуровневом смысле).
Вот есть ты, а есть твой псевдоним на форуме. Скажи мне, ты ссылка? Я так не думаю. А вот твой псевдоним - да. Он - ссылка, на тебя.
Определение переменной создает объект этой переменной. Он первичен, ссылка - вторична.

PS. Объявление навроде int a = 5; также является и определением. Но это уже то, о чем лучше позже. А то ты точно меня не отпустишь уже
1
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 15:40  [ТС] 18
Цитата Сообщение от DrOffset Посмотреть сообщение
Ссылка - это псевдоним переменной (в высокоуровневом смысле).
Вот есть ты, а есть твой псевдоним на форуме. Скажи мне, ты ссылка? Я так не думаю. А вот твой псевдоним - да. Он - ссылка, на тебя.
Объявление переменной создает объект этой переменной. Он первичен, ссылка - вторична.
Разница лишь в абстракции? Работаем-то с адресами в любом случае? И что ссылка, что "объект переменной" будут указывать на один и тот же адрес, будут совершать одни и те же допустимые операции. Ведь, используя переменные вне контекста их объявлений, мы даже не задумываемся где оригинальная ссылка. Работаем же с адресами-ссылками. В чём я ошибаюсь? Как мне тогда называть "ссылку, инициализированную объектом"? Ну, ладно, переменная. Но это общее же понятие...
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
23.08.2016, 15:44 19
Цитата Сообщение от Lyosha12 Посмотреть сообщение
Работаем-то с адресами в любом случае? И что ссылка, что "объект переменной" будут указывать на один и тот же адрес, будут совершать одни и те же допустимые операции. Ведь, используя переменные вне контекста их объявлений, мы даже не задумываемся где оригинальная ссылка. Работаем же с адресами-ссылками.
Да, если отойти от абстракций и несколько все упростить (забыть про оптимизации компилятора, про переменные в регистрах, про вычисление на этапе компиляции), то да. Работаем с адресами.
0
41 / 41 / 11
Регистрация: 02.04.2016
Сообщений: 313
23.08.2016, 15:46  [ТС] 20
Цитата Сообщение от DrOffset Посмотреть сообщение
Но это уже то, о чем лучше позже. А то ты точно меня не отпустишь уже

Не по теме:

Форумы за тем и нужны, что можно не отвечать сразу :D



Добавлено через 58 секунд
В любом случае, спасибо, что указали на пробелы
0
23.08.2016, 15:46
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.08.2016, 15:46
Помогаю со студенческими работами здесь

Инициализация полей объекта в заголовочном файле против списка инициализации
Говорят, что делать так не хорошо //.h class Foo { int intField = 5; public: ...

Warning C4244: инициализация: преобразование "__int64" в "int", возможна потеря данных
Что за предупреждение вылезает? Как исправить? (16 строка): warning C4244: инициализация:...

Возможна ли инициализация объекта класса в момент передачи параметра в
Пример конструкции, которую я хочу заставить работать Call Me.addButton(new...

Возможна ли инициализация связного списка в функции void (void)?
Всем привет. В связи с полученным в универе заданием возник вопрос, а возможна ли в принципе...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru