Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.60/10: Рейтинг темы: голосов - 10, средняя оценка - 4.60
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
1

Как работает компилятор при создании объекта

25.10.2013, 13:06. Просмотров 1768. Ответов 36
Метки нет (Все метки)

Таки думал разобрался как работает конструктор копирования, а выходит, что нет.
Вопрост состоит в следующем. Имеем код представляющий собой класс для хранения указателей на строки которые хранятся в другом классе(суть в том что бы не хранить в памяти несколько копия строк если они идентичны):
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<iostream>
using namespace std;
////////////////////////////////////////////////////////
class strCount
{
private:
    char* str;
    int count;
    friend class String;
    strCount(char * s)
    {
        str = new char [strlen(s) + 1];
        strcpy(str, s);
        count++;
    }
    ~strCount()
    {
        delete [] str;
    }
};
///////////////////////////////////////////////////
class String
{
private:
    strCount* psc;
public:
    String()
    {
        psc = new strCount("NULL");
    }
 
    String(char* s)
    {
        psc = new strCount(s);
    }
 
    String(String& S)
    {
        psc = S.psc;
        (psc->count)++;
    }
 
    ~String()
    {
        if(psc->count == 1)
            delete psc;
        else
            (psc->count)--;
    }
    String& operator = (String& S)
    {
        if(psc->count == 1)
            delete psc;
        else
            (psc->count)--;
        psc = S.psc;
        (psc->count)++;
        return *this;
    }
    void display()
    {
        cout << psc->str << endl;
    }
};
////////////////////////////////////////////////////
int main()
{
    system("chcp 1251>0");
    String s3 = "Немного лет тому назад, там где сливаяся шумят";
 
    cout << "s3= "; s3.display();
    return 0;
}

Когда я в первый раз читал Лафоре этот код отлично компилился(в то время я работал в VS 6.0).
В данный момент я программирую в среде Code::Blocks и в ней данный код не компилится. Ругается на неоднозначное определение конструктора. Вот отсюда и вопрос:
А что собственно происходит при создании объекта?
Когда запускается конструктор копирования, а когда конструктор с одним аргументом?
Все это время я полагал, что сперва запускается конструктор копирования, а вот он в свою очередь вызывает конструктор с одним аргументом.
Таки все же я не прав или как? Просвятите пожайлуста.

Добавлено через 5 минут
Странно. Конструктор копирования в VS не вызывается...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.10.2013, 13:06
Ответы с готовыми решениями:

Компилятор выдает ошибку при создании списка
Доброго времени суток всем, не могу понять где ошибка создаю список list...

При объявлении объекта компилятор требует ';'
Есть следующая программа(не законченная): #include &quot;stdafx.h&quot; #include...

Ошибка при создании объекта класса
Здравствуйте. В коде ниже при попытке вывести код на экран возникает следующая...

Ошибка при создании объекта класса
Приветствую, форумчане! Возник вопрос при создании объекта класса String. Что...

Undefined reference при создании объекта
Есть класс Engine и функция для его инициализации - CreateEngine при попытке...

36
Raali
639 / 343 / 74
Регистрация: 06.07.2013
Сообщений: 1,107
Завершенные тесты: 1
25.10.2013, 13:13 2
Цитата Сообщение от Ilot Посмотреть сообщение
Странно. Конструктор копирования в VS не вызывается...
Цитата Сообщение от Ilot Посмотреть сообщение
String s3 = "Немного лет тому назад, там где сливаяся шумят";
это обычный конструктор
C++
1
String(char* s)
0
novi4ok
551 / 504 / 25
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
25.10.2013, 13:17 3
copy constructor применяется, например, так:

C++
1
2
MyClass ob;
MyClass copy = ob;
у тебя перегружен оператор =, я не могу точно сказать, что произойдет с твоим классом в этом случае. поисследуй, разберись, расскажешь.
0
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 13:20  [ТС] 4
Цитата Сообщение от novi4ok Посмотреть сообщение
у тебя перегружен оператор =, я не могу точно сказать, что произойдет с твоим классом в этом случае. поисследуй, разберись, расскажешь.
Методом научного тыка выяснилось, что компилятор VS таки адекватно подходит к выбору конструктора:
Тута вызывется конструктор с одним аргументом:
C++
1
    String s3 = "Немного лет тому назад, там где сливаяся шумят";
А здеся конструктор копирования:
C++
1
    String s1(s3);
Так чего от меня хочет Code::Blocks? Как работает его компилятор? Т.е. я хочу спросить как определено поведение компилятора с точки зрения стандарта?

Добавлено через 53 секунды
Цитата Сообщение от novi4ok Посмотреть сообщение
у тебя перегружен оператор =, я не могу точно сказать, что произойдет с твоим классом в этом случае. поисследуй, разберись, расскажешь.
Не. Перегрузка оператора тут не причем. Это разные вещи.
0
Raali
639 / 343 / 74
Регистрация: 06.07.2013
Сообщений: 1,107
Завершенные тесты: 1
25.10.2013, 13:24 5
Цитата Сообщение от Ilot Посмотреть сообщение
Как работает его компилятор?
смотря какой в нем компилятор
0
castaway
Эксперт С++
4932 / 3038 / 454
Регистрация: 10.11.2010
Сообщений: 11,117
Записей в блоге: 10
Завершенные тесты: 1
25.10.2013, 13:28 6
Цитата Сообщение от Raali Посмотреть сообщение
смотря какой в нем компилятор
Обычно GCC.

Ilot, ты много всего к кучу смешал. Давай рассмотрим вариант попроще:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <cstring>
 
class A {
    char m_data[256];
 
public:
 
    A( char * s ) {
        strcpy( m_data, s );
    }
 
    A( A & a ) {
        strcpy( m_data, a.m_data );
    }
};
 
int main() {
    A a = "test";
}
Здесь Code::Blocks скорее всего выведет ошибку. Но если в конструкторе перед типом аргумента поставить const то он его съест.
1
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 13:28  [ТС] 7
Цитата Сообщение от Raali Посмотреть сообщение
смотря какой в нем компилятор
Ну так таки в Code::Blocks я пробывал несколько компиляторов: GCC, MV C++ 2005, MV C++ 2010. Все кричат об одно и том же.
0
ForEveR
В астрале
Эксперт С++
7996 / 4755 / 651
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
25.10.2013, 13:47 8
Raali, Отнюдь, строка которая вы процитировали
C++
1
String s3 = "Немного лет тому назад, там где сливаяся шумят";
Является ничем иным как
C++
1
String s3(String("Немного лет тому назад, там где сливаяся шумят"));
Конструктор копии вызывается, но на самом деле вызов не обязателен (copy-elision).

Добавлено через 30 секунд
novi4ok, Это не является вызовом конструктор копирования, это именно вызов оператора присваивания.

Добавлено через 3 минуты
Ilot, Код не будет компилироваться ни на одном нормальном компиляторе. Компилятор, даже если не вызывает конструктор копирования ОБЯЗАН проверить, что подходящий конструктор копирования существует. Здесь же, из-за того, что конструктор копирования принимает ссылку, нужного конструктора копирования нет, т.к. нельзя привести временный объект к ссылке (в MSVC это компилируется, потому что он допускает как расширение биндинг временного объекта к ссылке).
2
novi4ok
551 / 504 / 25
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
25.10.2013, 13:49 9
Цитата Сообщение от ForEveR Посмотреть сообщение
Это не является вызовом конструктор копирования, это именно вызов оператора присваивания.
ошибаешься, таки копирования. оператор присваивания вызывается здесь:

C++
1
2
3
MyClass ob;
MyClass ob2;
ob = ob2;
0
ForEveR
В астрале
Эксперт С++
7996 / 4755 / 651
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
25.10.2013, 13:51 10
novi4ok, Да, извиняюсь, согласен, затормозил. Не заметил, что идет инициализация, а не присваивания уже созданному объекту.
0
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 13:54  [ТС] 11
Мда castaway сделал как вы сказали заработало как я и говорил в первом посте. Т.е. сперва вызывается конструктор копирования, затем конструктор с одним аргументом. Насколько я понимаю конструктор копирования вызывается так как аргумент это константный указатель и конструктор копирования более подходит к данной ситуации. Однако почему в исходном варианте не вызывается конструктор с одним аргументом - ведь он в точности соответствует аргументам?
0
ForEveR
В астрале
Эксперт С++
7996 / 4755 / 651
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
25.10.2013, 13:57 12
Ilot,
Цитата Сообщение от Ilot Посмотреть сообщение
Т.е. сперва вызывается конструктор копирования, затем конструктор с одним аргументом.
Вообщем-то наоборот. Сначала с одним аргументом, а потом конструктор копирования с передачей в него вновь созданного объекта.
0
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 14:03  [ТС] 13
Цитата Сообщение от ForEveR Посмотреть сообщение
Ilot,
Вообщем-то наоборот. Сначала с одним аргументом, а потом конструктор копирования с передачей в него вновь созданного объекта.
Снова ошибаетесь уважаемый Сперва именно копирования, который вызывает с одним. Проверенно:
0
Миниатюры
Как работает компилятор при создании объекта  
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 14:06  [ТС] 14
Цитата Сообщение от ForEveR Посмотреть сообщение
Здесь же, из-за того, что конструктор копирования принимает ссылку, нужного конструктора копирования нет, т.к. нельзя привести временный объект к ссылке (в MSVC это компилируется, потому что он допускает как расширение биндинг временног
Я в замешательстве... А разве в конструкторе копирования можно передавать аргумент по значению?
Не приведет ли это к ошибке?
0
castaway
Эксперт С++
4932 / 3038 / 454
Регистрация: 10.11.2010
Сообщений: 11,117
Записей в блоге: 10
Завершенные тесты: 1
25.10.2013, 14:07 15
Цитата Сообщение от ForEveR Посмотреть сообщение
Вообщем-то наоборот.
Да, мне тоже сначала так показалось.. Но по факту вызывается только один конструктор A( char * s ), что по-сути вроде как и является правильным. Зачем тут конструктор копирования?
Единственный момент, который еще следует поправить, так это изменить конструктор на A( const char * s )
Поправьте если в чем-то ошибся.

Ilot, я предлагаю рассматривать вариант попроще, например мой, и уже от него отталкиваться.
1
ForEveR
В астрале
Эксперт С++
7996 / 4755 / 651
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
25.10.2013, 14:08 16
Ilot, Я говорю, что должно происходить по стандарту. Что вызывается в конкретной реализации меня мало интересует. Да и вообще по вашему скрину все так как я и сказал, сначала конструктор с одним параметром, потом конструктор копии.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
class Copyable
{
public:
   Copyable(int) { std::cout << "Constructor" << std::endl; }
   Copyable(const Copyable&) { std::cout << "Copy" << std::endl; }
};
 
int main()
{
   Copyable c = 1;
}
Bash
1
2
3
4
g++ -o new new.cpp -fno-elide-constructors
./new
Constructor
Copy
1
castaway
Эксперт С++
4932 / 3038 / 454
Регистрация: 10.11.2010
Сообщений: 11,117
Записей в блоге: 10
Завершенные тесты: 1
25.10.2013, 14:12 17
ForEveR, в твоём примере из 16-го поста у меня выводится только Constructor.
GCC 4.8.2 (-Wall -Wextra -pedantic -O0)

.. пардон, не заметил -fno-elide-constructors
0
ninja2
969 / 188 / 32
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
25.10.2013, 14:12 18
Цитата Сообщение от Ilot Посмотреть сообщение
Все это время я полагал, что сперва запускается конструктор копирования, а вот он в свою очередь вызывает конструктор с одним аргументом.
Конструктор копирования вызывается когда копируется объект например:
C++
1
2
A aa(7);//тут конструктор преобразования
A aa1(aa); //тут конструктор копирования
Аргументов у конструктора преобразования может быть сколько угодно.

А неоднозначность от похоже простой пример есть допустим у объекта А конструктор преобразования из double и оператор приведения в double, и если мы запишем например что то врде так:
C++
1
2
A aa;
A bb(a); //тут должно быть неоднозначность две функции могут вызваться как (double) так и A(const A&)
Это может быть пример простецкий да и компиляторы ругаются не все на него возможно, ни в этом примере где вызов конструктора копирования, от не помню вроде если так не будет ругаться то можно записать другой пример:
C++
1
double c=aa+3.14+bb;
тут снова не понятно во что их приводить, то ли double 3.14 приводить к A или наоборот объекты типа A приводить к double.

Все ошибки по неоднозначности легко устраняются применив явный вызов да и все.
0
Ilot
Эксперт С++
1831 / 1189 / 342
Регистрация: 16.05.2013
Сообщений: 3,139
Записей в блоге: 5
Завершенные тесты: 1
25.10.2013, 14:18  [ТС] 19
Уважаемый ForEveR может быть я не прав. Однако я считаю, что, пусть даже в вашем коде, сперва будет вызван конструктор копирования, однако встретив аргумент не соответствующий сигнатуре компилятор ищет подходящий конструктор в данном случае с одним аргументом (ук. на char). Поэтому сперва вызывается конструктор копирования, который в свою очередь вызовет конструктор с одним аргументом и затем управление снова вернется к конструктору копирования и будет выполнен его код. Вот именно поэтому сперва идет сообщение от конструктора с одним аргументом, а затем от конструктора копирования.
castaway, полностью с вами солидарен. Мне бы разъяснить, если вам не сложно, почему в этом случае выбирается конструктор копирования. Собственно я и просил вас об этом в 11 посте.
Цитата Сообщение от ForEveR Посмотреть сообщение
Ilot, Я говорю, что должно происходить по стандарту.
Вот это я и спрашивал. Осталось только выяснить почему компилятор Code:Blocks'а ведет себе иначе...
0
ninja2
969 / 188 / 32
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
25.10.2013, 14:21 20
Цитата Сообщение от Ilot Посмотреть сообщение
Однако я считаю, что, пусть даже в вашем коде, сперва будет вызван конструктор копирования, однако встретив аргумент не соответствующий сигнатуре компилятор ищет подходящий конструктор в данном случае с одним аргументом (ук. на char).
Нет в твоем коде вызывается вначале конструктор преобразования, затем конструктор копирования, потом оператор присваивания.
Явно все вызови и голову не морочь перепиши эту строчку:
C++
1
String s3 = "Немного лет тому назад, там где сливаяся шумят";
Она эквивалентна:
C++
1
String s3(operetor=(String("Немного лет тому назад, там где сливаяся шумят")));
0
25.10.2013, 14:21
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.10.2013, 14:21

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

Ошибка LNK2019 При динамическом создании объекта
Это хидер который я создал #include&lt;math.h&gt; #define PI 3.14 class Figure...

Ошибки при создании объекта в другом файле
a.h struct Coords { int x; int y; Coords() {}; Coords(int mX, int...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru