Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
 Аватар для oobarbazanoo
7 / 30 / 9
Регистрация: 13.05.2015
Сообщений: 1,835

Почему в данном случае срабатывает неявный конструктор

15.02.2018, 01:20. Показов 2270. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Почему в данном случае срабатывает неявный конструктор, хотя он и помечен explicit?

Main.cpp:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Hugo.h"
 
Hugo f();
 
Hugo f() {
    Hugo h;
    return HugoCopy(h);
}
 
int main(void) {
 
    return 0;
}
Hugo.h:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Hugo {
public:
    Hugo() {  }  
    explicit Hugo(Hugo const&) {  }
};
 
struct HugoCopy { 
    HugoCopy(Hugo const& hugo) 
      :hugo(hugo)
    { }
    operator Hugo const&() { return hugo; }
 
private:
    Hugo const& hugo;
};
Добавлено через 23 секунды
Взял отсюда: https://stackoverflow.com/ques... 03#4285803.

Добавлено через 8 минут
После дебага заметил что тут выходит почему-то одновременно с вызовом конструктора:
C++
1
2
3
HugoCopy(Hugo const& hugo) 
      :hugo(hugo)
    { }
Сразу после происходит вызов оператора:

C++
1
 operator Hugo const&() { return hugo; }
Кто знает, подскажите, пожалуйста, почему.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
15.02.2018, 01:20
Ответы с готовыми решениями:

Как правильно вызвать конструктор вектора в данном случае?
#include <iostream> #include <fstream> #include <map> #include <vector> #include <string> using namespace std; typedef...

Почему нужен   в данном случае?
Привет всем!Собственно такой вопрос:Почему в данном случае нужен   ? И у меня при написании дескриптора <wbr>строка...

Почему типы-параметры нельзя вывести в данном случае?
static class S { public static T2 Select<T, T2>(T source, Func<T, T2> f) => new T2; public static void P() => Select(new...

20
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
15.02.2018, 01:39
Цитата Сообщение от oobarbazanoo Посмотреть сообщение
Почему в данном случае срабатывает неявный конструктор, хотя он и помечен explicit?
Ничего не понятно. У вас в коде нет никаких предпосылок для использования вашего explicit конструктора. С чего вы взяли, что он у вас "срабатывает"? Где?

У вас в коде открытым тестом прописано использование конструктора HugoCopy(Hugo const& hugo) и оператора operator Hugo const&(). А они никакие не explicit.
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 01:51
TheCalligrapher, думаю, он о том, что
C++
1
2
3
4
Hugo f() {
    Hugo h;
    return HugoCopy(h);
}
При возврате из функции для построения объекта типа Hugo необходимо неявно преобразовать HugoCopy в Hugo, но конструктор копирования Hugo является explicit и поэтому неявное преобразование должно быть невозможно. Кстати, gcc и vc, код не собирают, в отличии от clang.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
15.02.2018, 02:02
Цитата Сообщение от Croessmah Посмотреть сообщение
необходимо преобразовать HugoCopy в Hugo, но конструктор копирования Hugo является explicit и поэтому неявное преобразование должно быть невозможно.
Хм... В данном случае преобразование HugoCopy обратно в Hugo делается через operator Hugo const&(), т.е. с преобразованием как таковым проблем нет. У меня этот код прекрасно собирается и в gcc и в clang.

Более того, даже если добавить Hugo p = f(); в main, то код собирается gcc в режиме C++17, но не собирается в режиме C++14 (именно из-за конструктора копирования), что по-видимому вызвано guaranteed copy elision в C++17.

Добавлено через 3 минуты
Хотя да, вижу что конструктор копирования вызывается в gcc...
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 02:03
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
HugoCopy обратно в Hugo делается через operator Hugo const&()
Но для построения объекта необходим конструктор копирования, который explicit.
gcc: http://rextester.com/FRWIK38971
vc: http://rextester.com/FNLWAA35042
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
15.02.2018, 02:09
Цитата Сообщение от oobarbazanoo Посмотреть сообщение
Почему в данном случае срабатывает неявный конструктор, хотя он и помечен explicit?
У меня не компилируется. Я думаю это потому что f возвращает не ссылку а копию. А конструктора допускающего преобразование нет.

То есть, константная ссылка на локальный объект потребует копирования для возврата из такой функции. Например можно и так написать. Тут явно видно что происходит. Не желает конструктор копии преобразовывать константную ссылку в аргумент требующий Hugo h. Тут конечно забавно всё выглядит так как объявлен то он именно как ссылка на константу. Но объявление ссылки аргумента функции это не объявление типа, а декларация контракта - не менять аргумент. В функции инициализируется ссылка, но ожидается внешний объект. Это поведение касается именно константной ссылки.
C++
1
2
3
4
Hugo f(){
const Hugo& h = Hugo();
return h;
}

Не по теме:

Пардон. До моего поста выступлений ещё не было. Впрочем, я уверен в том, что говорю не менее чем обычно. То есть сомневаюсь как всегда. :pardon:

0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 02:13
the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization (11.6) from the operand.
C++
1
2
3
4
5
int main()
{
    Hugo h(HugoCopy(h));//direct-initialization - ok
    Hugo h = HugoCopy(h);//copy-initialization - ошибка
}
1
 Аватар для tmpValue
41 / 75 / 15
Регистрация: 04.10.2017
Сообщений: 283
15.02.2018, 02:24
oobarbazanoo, потому что hugo надо заменить на hoggy.
4
15.02.2018, 02:27

Не по теме:

Цитата Сообщение от tmpValue Посмотреть сообщение
потому что hugo надо заменить
Причём вызывать явно и никак иначе. Про преобразования я зря понаписал. :pardon:

0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 02:27
TheCalligrapher, в return statement должна быть copy-initialization.
A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters (if any) to the type of its class. Such a constructor is called a converting constructor .
...
A non-explicit copy/move constructor (15.8) is a converting constructor.
For copy-initialization, the candidate functions are all the converting constructors (15.3.1) of that class.
то есть при copy-initialization explicit Hugo(Hugo const&) не должен быть кандидатом, но если return HugoCopy(h) собирается, значит в return statement используется не copy-initialization, верно?
1
 Аватар для oobarbazanoo
7 / 30 / 9
Регистрация: 13.05.2015
Сообщений: 1,835
15.02.2018, 14:46  [ТС]
tmpValue, почему на hoggy? Не нахожу перевода или значения данного слова. Объясните данный момент, пожалуйста.

Добавлено через 1 минуту
Croessmah, в этом то и вопрос. Как?

Добавлено через 4 минуты
Croessmah, подскажите, пожалуйста, как Вы смогли сделать так, что бы Ваш код сохранился для тех кто перейдёт по ссылке на онлайн компилятор?
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 17:10
Цитата Сообщение от oobarbazanoo Посмотреть сообщение
почему на hoggy? Не нахожу перевода или значения данного слова.
Может у него и спросим? hoggy, выходи, дорогой.
Цитата Сообщение от oobarbazanoo Посмотреть сообщение
как Вы смогли сделать так, что бы Ваш код сохранился для тех кто перейдёт по ссылке на онлайн компилятор?
Как правило, облачные компиляторы умеют это. Где-то кнопочка save, где-то fork, где-то share...

Добавлено через 1 минуту
Цитата Сообщение от oobarbazanoo Посмотреть сообщение
Croessmah, в этом то и вопрос. Как?
Ну так мне тоже интересно. Возможно, TheCalligrapher, сможет объяснить.
Или DrOffset, или ct0r.
На удачу позову еще FoReVeR и Tulosba.
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
15.02.2018, 19:07
Цитата Сообщение от Croessmah Посмотреть сообщение
Может у него и спросим? hoggy, выходи, дорогой.
привеееет))


по теме: не должно компиляццо.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
15.02.2018, 19:16
Цитата Сообщение от hoggy Посмотреть сообщение
по теме: не должно компиляццо.
Дык и не компилится. Однако не ясно почему вот так:
C++
1
2
A b;
A a = b;//неявный вызов
в то время как в функциональном стиле - explisit работает нормально.
Оно же и при возврате из функции по значению получается неявным вызовом... Ну то есть, такое чувство, что гарантия что не появится приведение только при вызове:
C++
1
A a(b);
иначе параметр будет обнюхиваться и может быть приведен. В С++ приведение к себе - не преступление, конечно, но похоже что exlisit счтает и это вольностью.
Понимаю что бредово, но вот как ещё это можно объяснить?
1
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 19:31
Цитата Сообщение от IGPIGP Посмотреть сообщение
в то время как в функциональном стиле - explisit работает нормально.
Потому что по правилам языка в direct-initialization A a(b) explicit конструкторы будут рассматриваться как кандидаты при выборе конструктора, а в copy-initialization A a = b; explicit-конструкторы не являются кандидатами.

Добавлено через 44 секунды
Цитата Сообщение от IGPIGP Посмотреть сообщение
Дык и не компилится.
clang собирает
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
15.02.2018, 19:42
Цитата Сообщение от Croessmah Посмотреть сообщение
Потому что по правилам языка
Вот-вот. Словосочетание "правилам языка" - ключевое. Это в общем и целом означает "потому что". Фактически операторная форма вызова:
A a= b;
однозначно эквивалентна
A a(a);
и не должно быть разницы. Различие то тут (насколько я понимаю) только в синтаксисе, а вызов то однозначен? Просто компиллятору нужно бы быть чуть-чуть умнее.
Цитата Сообщение от Croessmah Посмотреть сообщение
clang собирает
и выясняется, что такой компилятор есть.
Странно это. Но нужно запомнить.
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
15.02.2018, 19:45
Цитата Сообщение от IGPIGP Посмотреть сообщение
однозначно эквивалентна
Не эквивалентна. Это два разных вида инициализации. Это четко прописано в стандарте языка.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
15.02.2018, 19:50
Цитата Сообщение от Croessmah Посмотреть сообщение
Не эквивалентна.
Я имел ввиду случай когда есть определённый пользователем конструктор копии (тот что в топике случай). Конструктор преобразования с аргументом своего типа, то есть. Насколько мне известно при вызове:
A a=b;
должен вызваться именно он и ни какой другой. Если это не так, то это и есть ответ на вопрос топика.
0
285 / 176 / 21
Регистрация: 16.02.2018
Сообщений: 666
29.04.2018, 03:24
Цитата Сообщение от Croessmah Посмотреть сообщение
При возврате из функции для построения объекта типа Hugo необходимо неявно преобразовать HugoCopy в Hugo, но конструктор копирования Hugo является explicit и поэтому неявное преобразование должно быть невозможно.
Не всё так однозначно. Конечно, return e — это copy-initialization.
Только вот в зависимости от типа (и value category) e правила разные.
В данном случае, возвращаемый тип у функции — это тип-класс.
Поэтому смотрим в
Цитата Сообщение от http://eel.is/c++draft/dcl.init#17.6
If the destination type is a (possibly cv-qualified) class type:
(17.6.1) — If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.
[ Example: T x = T(T(T())); calls the T default constructor to initialize x. — end example]
(17.6.2) — Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered.
The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution.
The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s).
If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.
(17.6.3) — Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in [over.match.copy], and the best one is chosen through overload resolution.
If the conversion cannot be done or is ambiguous, the initialization is ill-formed.
The function selected is called with the initializer expression as its argument; if the function is a constructor, the call is a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor.
The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.
Если тип у e — тот же (игнорируя cv-квалификаторы) тип-класс, что и инициализируемый (возвращаемый), и e это не prvalue (пункт (17.6.1)), то применяется (17.6.2) и, конечно, explicit-конструктор не подойдёт.

Но в случае return HugoCopy(h) действует пункт (17.6.3)
Пункт ссылается на [over.match.copy]
Цитата Сообщение от http://eel.is/c++draft/over.match.copy
1 Under the conditions specified in [dcl.init], as part of a copy-initialization of an object of class type, a user-defined conversion can be invoked to convert an initializer expression to the type of the object being initialized.
Overload resolution is used to select the user-defined conversion to be invoked.
[ Note: The conversion performed for indirect binding to a reference to a possibly cv-qualified class type is determined in terms of a corresponding non-reference copy-initialization. — end note]
Assuming that “cv1 T” is the type of the object being initialized, with T a class type, the candidate functions are selected as follows:

(1.1) The converting constructors of T are candidate functions.
(1.2) When the type of the initializer expression is a class type “cv S”, the non-explicit conversion functions of S and its base classes are considered.
When initializing a temporary object ([class.mem]) to be bound to the first parameter of a constructor where the parameter is of type “reference to possibly cv-qualified T” and the constructor is called with a single argument in the context of direct-initialization of an object of type “cv2 T”, explicit conversion functions are also considered.
Those that are not hidden within S and yield a type whose cv-unqualified version is the same type as T or is a derived class thereof are candidate functions.
Conversion functions that return “reference to X” return lvalues or xvalues, depending on the type of reference, of type X and are therefore considered to yield X for this process of selecting candidate functions.

2 In both cases, the argument list has one argument, which is the initializer expression.
[ Note: This argument will be compared against the first parameter of the constructors and against the implicit object parameter of the conversion functions. — end note]
(1.1) не даёт ничего, т.к. никаких converting functions у Hugo нет.
(1.2) даёт нам candidate function HugoCopy::operator Hugo const&.
Эта функция, с аргументом HugoCopy(h), используется для инициализации: "The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization".

Это свежий драфт. В драфте n1905 от 2005-го года сказано, в принципе, то же самое:
The result of the call (which is the temporary for the constructor case) is then used to direct-initialize,
according to the rules above, the object that is the destination of the copy-initialization
Цитата Сообщение от hoggy Посмотреть сообщение
по теме: не должно компиляццо.
Точнее, должно.

Добавлено через 22 часа 59 минут
Самое забавное, что Croessmah 2.5 года назад цитировал нужное место стандарта и даже подчеркнул:
Цитата Сообщение от Croessmah Посмотреть сообщение
The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized
но в этом топике старательно всех убеждает, что код компилироваться не должен.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
29.04.2018, 08:42
Последнее, скорее всего относится к копи-элизиум оптимизации и к данному случаю не относится. Я не уверен, потому и пишу "скорее всего". В нашем случае (опять же - по идее) имеет место быть возможность прямого указания компилятору - применять копирующий конструктор только для случаев его явного вызова. Это может быть нужно, например, когда операция присаивания и копирующий конструктор работают с ресурсами по разному.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.04.2018, 08:42
Помогаю со студенческими работами здесь

[C]Почему bind в данном случае выдаёт ошибку Address already in use?
Пытаюсь разобраться с темой сокетов. Есть клиент и сервер,которые связываются через STREAM сокет. Принцип такой: Сервер ожидает входящих...

Почему в данном коде не срабатывает присвоение
Всем привет, подскажите пожалуйста почему в данном коде не срабатывает присвоение shouldStartChecks=true и на экран всегда...

Почему в данном случае ставится двойной нижний пробел __ в цикле for?
>>> def fib(n): a = 0 b = 1 for __ in range(n): a = b + b return a >>>

Почему в данном случае работа с заранее выделенной памятью медленнее чем с динамической?
Написал функцию которая на основе списка выделяет память и при каждом вызове возвращает указатель на следующий элемент для объекта. Код...

Почему не срабатывает конструктор копирования в пользовательском классе
вроде со всем разобралась, но не заходит в конструктор копирования. В чём ошибка? #include <iostream> #include...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США. Нашел на реддите интересную статью под названием «Кто-нибудь знает, где получить бесплатный компьютер или. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru