Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
1

Метод в конструкторе вызывается задолго после создания объекта

28.06.2019, 14:52. Показов 3763. Ответов 27

Author24 — интернет-сервис помощи студентам
Не знаю как загуглить это, поэтому обращаюсь к живым людям.
Есть классы Group, Student, Subject. Group хранит вектор Student'ов, Student хранит вектор Subject'ов. Мы имеем вектор Group'ов.
Дальше кодом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Тут конструкторы классов
 
Group::Group(std::string _path, std::string _name):
    objectSchool(_path, _name){
    students.clear();
    createStudents();
}
Student::Student(std::string _path, std::string _name):
    objectSchool(_path, _name) {
    subjects.clear();
    createSubjects();
}
Subject::Subject(std::string _path, std::string _name):
    objectSchool(_path, _name){
    readFromFile(name);
}
Как видим, при создании Subject, вызывается метод readFromFile(). В методе есть printf, который выводит "1"
C++
1
2
3
4
5
6
7
//Это живет в main
 
std::vector<Group> groups;
for(std::string name : files){
    groups.push_back(Group(path, name));
    groups.back().writeAllInfo();
}
Метод writeAllInfo() выводит "2"

Однако в консоли, порядок не такой. Выводится наоборот:
C++
1
2
3
4
5
//Console
2
2
2
1
Причем вывод "2" происходит нормально, а вывод "1" мало того, что единожды (хотя должно быть многократно), так еще и после вывода "2".

Сначала думал, что это из-за std::vector<Group>. Исправил на std::vector<Group*> (и так с каждым вложенным вектором). Дело оказалось не в этом.

Предполагаю, что это из-за механики с++, о которой я еще не знаю (конструкторы в векторе = магия). Однако, я помню про предыдущее замечание с "утками, гусями..", поэтому если нужен полный код, пишите - скину. Сейчас не хочу засорять вопрос.

(Чувствую опять билеберду написал)

Добавлено через х минут
Кстати, в чем отличие между vector<C> и vector<C*> ?
Понятно, что во втором случае объект по ссылке передается. Однако очевидную разницу я не заметил
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.06.2019, 14:52
Ответы с готовыми решениями:

Задать метод в объекте класса после создания самого объекта
Есть class UC : UserControl, представляет из себя табличку, отображает разные данные и метод...

Как сделать камеру дочерним объектом после создания другого объекта, или отображение сцены после создания самой камеры?
Есть кнопка при нажатии на неё создается куб ( с помощью Instantiate) как сделать камеру дочерним...

Какой метод вызывается при инициализации объекта
Всем привет. У меня есть функция которая возвращает объект класса Point. Point func() { ......

Как правильно вызывается метод SaveAs объекта ActiveWorkbook?
народ может кто подскажет как правильно вызывается метод SaveAs объекта ActiveWorkbook

27
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 15:01 2
Лучший ответ Сообщение было отмечено Moais как решение

Решение

Moais, честно говоря, ничего не понятно. Скорее всего у вас ошибка где-то в коде, который вы не показали

Цитата Сообщение от Moais Посмотреть сообщение
Понятно, что во втором случае объект по ссылке передается. Однако очевидную разницу я не заметил
Очевидная разница в том, что первом случае вектор хранит объект типа С, а во втором объект типа указатель на С.
Точно такой же вопрос можно было задать про то, чем отличается vector<int> и vector<double>. Ответ будет таким же, хранятся объекты разных типов.

Добавлено через 2 минуты
Вот, например, хотелось бы видеть как устроена функция createSubjects();
1
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
28.06.2019, 15:07 3
Цитата Сообщение от Moais Посмотреть сообщение
Как видим, при создании Subject, вызывается метод readFromFile(). В методе есть printf, который выводит "1"
А точно readFromFile выводит 1, а не 2? Проверь
0
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:12  [ТС] 4
DrOffset, сейчас покажу, что же у меня за фобия - код показывать? (Наступаю на те же грабли)
Как обзывать файлы кода? Нужно что-то внутри тегов [СРР] прописывать?

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
Group::Group(std::string _path, std::string _name):
    objectSchool(_path, _name){
    students.clear();
    createStudents();
}
void Group::writeAllInfo(){
    printf("%s (%zd)\n", name.c_str(), students.capacity());
    for(int i = 0; i < students.capacity(); ++i){
        students[i].writeAllInfo();
    }
}
int Group::createStudents(){
    std::vector<std::string> stdnts = sWhatInFolder(path + name);
 
    for(std::string _name: stdnts){
 
        bool repeat = false;
        for(int j = 0; j < students.capacity(); ++j){
 
            if(students[j].getName() == _name){
                repeat = true;
            }
        }
        if(!repeat){
            students.push_back(Student(path+name, _name));
        }
    }
    return (int)students.capacity();
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Student::Student(std::string _path, std::string _name):
    objectSchool(_path, _name) {
    subjects.clear();
    createSubjects();
}
 
void Student::writeAllInfo(){
    printf("  %s (%zd)\n", name.c_str(), subjects.capacity());
    for(int i = 0; i < subjects.capacity(); ++i){
        subjects[i].writeAllInfo();
    }
}
 
int Student::createSubjects(){
    std::vector<std::string> sbj = sWhatInFolder(path + name);
    for(std::string _name : sbj){
        bool repeat = false;
        for(int i = 0; i < subjects.capacity(); ++i){
            if(subjects[i].getName() == _name){ repeat = true; }
        }if(!repeat){ subjects.push_back(Subject(path + name, _name)); }
    }return (int)subjects.capacity();
}
Ниже будет строка printf("r = %d\n", rates[i].back()); в readFromFile. Она выводит типа"1"
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
Subject::Subject(std::string _path, std::string _name):
    objectSchool(_path, _name){
    *rateCount = {0};
    readFromFile(name);
}
 
void Subject::writeAllInfo(){
    printf("    %s", name.c_str());
    for(int i = 0; i < monthCount; ++i){
        printf("\n    %d", rateCount[i]);
        for(int j = 0; j < rateCount[i]; ++j){
            printf("%3d", rates[i][j]);
        }
    }
    printf("\n");
}
 
void Subject::readFromFile(std::string _name){
    name = _name;
    std::string fpath = path + name + ".txt";
 
    std::ifstream fin;
    fin.open(fpath.c_str());
    if (fin.is_open()){
        *mr = {0};//По идее тут мы обнуляем массив
        *rateCount = {0};
        std::string line;
        for(int i = 0; getline(fin, line) && i < 4; ++i){
            std::vector<std::string> r8s = split(line, ' ');//Имеем вектор оценок
            rateCount[i] = (int)r8s.capacity();
            mr[i] = 0;
 
        
            std::vector<int> temp;
            for(std::string r : r8s){
                if(r != "-"){
                    temp.push_back(int(r[0] - '0'));
                    mr[i] += temp.back();
                }else{
                    temp.push_back(10);//Чтобы знать, что это прочерк
                    continue;
                }
            }
            mr[i] /= rateCount[i];
            rates.push_back(temp);
////////////////// printf("r = %d\n", rates[i].back());///DEBUG
        }
        fin.close();
    }
 
}
На приложенном скрине то, как работает сейчас. Должно работать точно так же, только вместо "-858993460", должно быть примерно так: "4 5 3 4 4 3 5" - оценки студентов
Миниатюры
Метод в конструкторе вызывается задолго после создания объекта  
0
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:13  [ТС] 5
oleg-m1973, да, код ниже - докажет это: )
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 15:18 6
Лучший ответ Сообщение было отмечено Moais как решение

Решение

Будем разбираться итеративно.

Цитата Сообщение от Moais Посмотреть сообщение
C++
1
for(int j = 0; j < students.capacity(); ++j){
Это неверно. capacity() - это количество доступной памяти для элементов, а не количество элементов.
Количество элементов - это size()

Добавлено через 4 минуты
Цитата Сообщение от Moais Посмотреть сообщение
*mr = {0};//По идее тут мы обнуляем массив
Совсем нет. Тут вы обнуляете первый (нулевой элемент).
1
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:33  [ТС] 7
Хотел спросить: "Чем отличается capacity от size". Нашел вот это: Отличие size от capacity

Добавлено через five минут
DrOffset, окей, а без цикла никак не обнулить разом весь статический массив?

По поводу очередности вызовов.
"-858993460" - как понимаю, следствие не инициализированного массива.
Окей. Однако в методе readFromFile(), в строке rateCount[i] = (int)r8s.capacity(); (которая уже исправлена на size), мы видим, что i-му элементу присваивается значение. Почему же при вызове метода writeAllInfo() она опять без заданного значения?

Это точно не из-за отсутствия <Group*>?
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 15:33 8
Moais, я ж написал чем они отличаются
0
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:35  [ТС] 9
DrOffset, написали. Вот только я не уверен был, правильно ли понял, что за доступная память: )
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 15:36 10
Цитата Сообщение от Moais Посмотреть сообщение
а без цикла никак не обнулить разом весь статический массив?
Смотря какого типа. Для целых можно использовать memset.

Цитата Сообщение от Moais Посмотреть сообщение
"-858993460" - как понимаю, следствие не инициализированного массива.
Скорее всего.

Цитата Сообщение от Moais Посмотреть сообщение
Это точно не из-за отсутствия <Group*>?
Я так не думаю.

Цитата Сообщение от Moais Посмотреть сообщение
которая уже исправлена на size), мы видим, что i-му элементу присваивается значение. Почему же при вызове метода writeAllInfo() она опять без заданного значения?
Во-первых вы уверены. что везде убрали capacity? Он нигде в вашем коде не нужен.
Во-вторых кода все еще мало.
Давайте весь код в архиве.
0
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:39  [ТС] 11
DrOffset,
Во-первых, да, уверен. ctrl+f по всем 4-м документам (даже в закомменченых областях его нет).
Во-вторых, может проще ссылку на github?
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 15:40 12
Цитата Сообщение от Moais Посмотреть сообщение
Вот только я не уверен был, правильно ли понял, что за доступная память: )
Достаньте себе вот такой справочник (в каком угодно виде). И не используйте ни единой фукции из библиотек, пока не разберетесь что они точно делают.
Чем раньше вы привыкнете сначала внимательно читать документацию, а потом что-то делать, тем быстрее будет потом расти ваша зарплата (я не шучу).



Добавлено через 33 секунды
Цитата Сообщение от Moais Посмотреть сообщение
Во-вторых, может проще ссылку на github?
Это и лучше. Хотя бы буду видеть ваши изменения, если что.
1
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 15:45  [ТС] 13
DrOffset, полностью согласен с вами. Это моя извечная проблема - сначала делать, а потом читать
Правда, планирую устроиться на java-разработчика. Слышал, что у плювощиков заказов все меньше

Телепорт на гит
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 16:01 14
Moais, что-то у вас код на гитхабе отличается от того, что вы тут в теме показывали
0
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 16:04  [ТС] 15
Тьфу!
Я же не обновил его.

Все, можете проверить. В ветке main develoр
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 16:18 16
Moais, просто буду перечислять по порядку все, что увидел (запустить я ваш код все равно не могу)

C++
1
2
3
    for(int i = 0; i < students.size(); ++i){
        students[i].~Student();
        }
Удалить. Ручной вызов деструктора вам здесь совсем не нужен. Это грубая ошибка.

C++
1
students.clear();
В деструкторе - удалить. Деструктор вектора сделает это сам. В конструкторе тоже можно удалить. Вектор в момент конструирования всегда пустой.

C++
1
2
3
4
5
6
Subject::Subject(std::string _path, std::string _name):
    objectSchool(_path, _name){
    *rateCount = {0};
    readFromFile(name);
    ///printf("Alaska!\n");///DEBUG
}
В этом коде сделать так:
C++
1
2
3
4
5
Subject::Subject(std::string _path, std::string _name) :
    objectSchool(_path, _name), rateCount() 
{
    readFromFile(name);
}
1
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 20:03  [ТС] 17
DrOffset,
Цитата Сообщение от DrOffset Посмотреть сообщение
Ручной вызов деструктора здесь - грубая ошибка.
А почему это ошибка? std::vector сам вызывает деструкторы у элементов?

Цитата Сообщение от DrOffset Посмотреть сообщение
students.clear(); - удалить.
Разработчик std умнее меня


Цитата Сообщение от DrOffset Посмотреть сообщение
C++
1
2
3
4
5
Subject::Subject(std::string _path, std::string _name) :
    objectSchool(_path, _name), rateCount() 
{
    readFromFile(name);
}
objectSchool(_path, _name), rateCount() - вот это что-то новенькое! По-моему подобно объявляются константы, но для них еще значения указываются.
вот конкретно , rateCount() этот кусок вызывает непонимание. Что это за прием, как называется, что делает?

Добавлено почти сразу
Цитата Сообщение от Moais Посмотреть сообщение
вот конкретно , rateCount() этот кусок вызывает непонимание
Предполагаю, что он обнуляет массив (а сейчас еще и проверю), но как? Как это работает?
0
6107 / 3461 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
28.06.2019, 20:10 18
Лучший ответ Сообщение было отмечено Moais как решение

Решение

Цитата Сообщение от Moais Посмотреть сообщение
вот это что-то новенькое!
https://en.cppreference.com/w/... lizer_list
1
9 / 7 / 3
Регистрация: 03.02.2017
Сообщений: 124
28.06.2019, 20:13  [ТС] 19
DrOffset, последовал вашим советам. Да, действительно, таинственная запись обнуляет массив, но природа ее не ясна. Метод в конструкторе по-прежнему вызывается после

Добавлено через 2 минуты
zayats80888, мерси
0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
28.06.2019, 21:10 20
Цитата Сообщение от Moais Посмотреть сообщение
Метод в конструкторе по-прежнему вызывается после
Явный вызов деструкторов тоже убрали?

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

Добавлено через 7 минут
Moais, обновите версию на гитхабе с последними исправлениями. Я через часок еще раз гляну.
0
28.06.2019, 21:10
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.06.2019, 21:10
Помогаю со студенческими работами здесь

Не вызывается override метод при создании объекта через рефлексию
Воопщем у меня есть словарь, в котором записаны типы классов &lt;enum, System.Type&gt; Я по enum, чтоб...

В конструкторе вложенного класса инициализируется приватное поле. Потом вызывается функция-метод этого класса и выводит значение этого поля НО НЕ ТО!
Друзья! Почему так? #include &lt;windows.h&gt; #include &lt;iostream&gt; using namespace std; //Вот...

два раза вызывается событие live.() после load загрузки объекта jquery
два раза вызывается событие $(&quot;$btn&quot;).live(&quot;click&quot;,function()) после load загрузки объекта кнопки...

Не вызывается метод из базового типа после приведения типов?
При приведении типов от производного класса Manager к базовому классу Employee, у объекта &quot;e&quot; к...


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

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