Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: рекурсивный поиск файлов  (Прочитано 35008 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Ivan355
Новенький

ru
Offline Offline

« : 06-04-2017 11:36 » 

Всем доброго времени суток! Нужна ваша подсказка! Возникла проблема с рекурсивным поиском файлов. Накидал я функцию, но при работе выводит бесконечный список одинаковых файлоы и деректорий. Пытался переделать, были тоже ошибки выводился не весь список, или вообще ничего. Помогите доделать функцию, чтобы она работала правильно! Делал на основе примеров из гугла. В строках way_1, 2 и 3 храню путь. Вход функции search_file( "C:\\", "*.*"). Спасибо за помощь!!!
Код: (C++)
int search_file(string dir, string mask)
{
        const char white_list_1[] = "Programm Files";
        const char white_list_2[] = "Programm Files (x86)";
        const char white_list_3[] = "Windows";
        string way_1 = dir;
        string way_2 = dir;
        string way_3 = way_2;
    way_1 = way_1 + mask;
        HANDLE hand;
        WIN32_FIND_DATA data_file;
        hand = FindFirstFile((way_1).c_str(), &data_file);
        if (hand != INVALID_HANDLE_VALUE)
        {
                do
                {
                        if (lstrcmpA(data_file.cFileName, ".") == 0 || lstrcmpA(data_file.cFileName, "..") == 0)
                        {
                                continue;
                        }
                        if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || lstrcmpA(data_file.cFileName, white_list_2) == 0 || lstrcmp(data_file.cFileName, white_list_3) == 0)
                        {
                                continue;
                        }
                        if (data_file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
                        {
                                continue;
                        }
                        if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                        {
                                way_1 = dir + data_file.cFileName + '\\';
                                cout << "dir -" << way_1 << endl;
                                search_file(way_1, mask);
                        }
                        else
                        {
                                way_3 = way_3 + data_file.cFileName;
                                cout << "file-" << way_3 << endl;
                        }

                } while (FindNextFile(hand, &data_file));
                FindClose(hand);
        }
        return (1);
}
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 06-04-2017 13:03 » 

Можно увидеть весь код программы?

И, опечатка?
Код: (C++)
int search_file(string dir, string mask)
{
...
if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || \
lstrcmpA(data_file.cFileName, white_list_2) == 0 || \
lstrcmp(data_file.cFileName, white_list_3) == 0)
...
}
Везде lstrcmpA, кроме lstrcmp.
Записан
Ivan355
Новенький

ru
Offline Offline

« Ответ #2 : 06-04-2017 14:05 » 

Добрый день. Эта функция пока всё что у меня есть. В планах было после получения списка, что то делать с файлом, например нужный считывать или копировать. Я написал эту функцию и решил протестировать, в результате она не работает. Так и сижу на ней, пытаюсь понять что не так. Вродь нарыл, что нужно к пути добавить найденную папку и вызвать функцию снова, вродь так и делаю, а толку ноль. Да там ошибка, я забыл А в конце дописать...
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 06-04-2017 14:36 » 

Общие соображения таковы:

Когда Вы вызываете FindFirstFile, то он возвращает некий указатель, который в дальнейшем используется FindNextFile. Хранится hand, как переменная внутри функции, поэтому, когда происходит вложенный вызов это значение возможно изменится, и после возврата будет ссылаться на ветвь поиска, которая завершилась. Стало быть, хранить эту переменную нужно принудительно в стеке текущего вызова функции. Как это сделать лучше стоит поинтересоваться у более опытных участников.

Чтобы разобраться попробуйте создать тестовое дерево директорий для поиска без файлов:
С:\FIND_TEST\
    С:\FIND_TEST\1
    С:\FIND_TEST\2
        С:\FIND_TEST\2\21
        С:\FIND_TEST\2\22
    С:\FIND_TEST\3

Далее, привести на форуме весь код, и вывод консоли.

Для теста лучше упростить:
Код: (C++)
int search_file(string dir, string mask)
{
    string way = dir + mask;

    WIN32_FIND_DATA data_file;

    HANDLE hand = FindFirstFile((way).c_str(), &data_file);

    if (hand != INVALID_HANDLE_VALUE) {

        do {

            if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {

                way = dir + data_file.cFileName + '\\';
                cout << way << endl;
                search_file(way, mask);
            }

        } while (FindNextFile(hand, &data_file));

        FindClose(hand);
    }
    return (1);
}

Добавлено через 6 часов, 52 минуты и 40 секунд:
Немного попрактиковался, конечно, далеко от идеала, и на С:
Код: (C)
#include <stdio.h>
#include <malloc.h>
#include <windows.h>

char* stradd(char* first, char* second) {

    unsigned int size = strlen(first) + strlen(second) + 1;
    char* total = malloc(size);

    if (!total) return 0;

    char* dst = total;
    char* src = first;

    for (unsigned int i = 0; i < strlen(first); i++) {*dst++ = *src++;}

    src = second;

    for (unsigned int i = 0; i < strlen(second); i++) {*dst++ = *src++;}

    *dst = (char)0;

    return total;
}

void my_search_tree(char* dir, char* mask, int depth) {

    WIN32_FIND_DATA d;

    char* path = stradd(dir, mask);
    if (!path) return;

    /* printf("PATH: %s\n", path); */

    HANDLE h = FindFirstFile(path, &d);

    if (!h) return;

    do {

        if (d.cFileName[0] != '.') {

            if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {

                for (unsigned int j = 0; j < depth; j++) printf(" ");

                printf("FOUND: %s\n", d.cFileName);

                char* service = "\\";
                char* new_path_1 = stradd(dir, d.cFileName);

                if (!new_path_1) return;

                char* new_path_2 = stradd(new_path_1, service);

                if (!new_path_2) return;

                my_search_tree(new_path_2, mask, depth + 1);

                free(new_path_2);
                free(new_path_1);
            }
        }

    } while(FindNextFile(h, &d));

    free(path);
}

int main(int argc, char* argv) {

    my_search_tree("C:\\TDM64\\", "*.*", 0);

    return 0;
}

Результат:
FOUND: bin
FOUND: gdb32
 FOUND: bin
  FOUND: DLLs
  FOUND: lib
   FOUND: bsddb
   FOUND: compiler
   FOUND: ctypes
    FOUND: macholib
   FOUND: curses
   FOUND: distutils
    FOUND: command
   FOUND: email
    FOUND: mime
   FOUND: encodings
   FOUND: ensurepip
    FOUND: _bundled
   FOUND: hotshot
   FOUND: idlelib
    FOUND: idle_test
   FOUND: importlib
   FOUND: json
   FOUND: lib-tk
    FOUND: test
     FOUND: test_tkinter
     FOUND: test_ttk
   FOUND: lib2to3
    FOUND: fixes
    FOUND: pgen2
    FOUND: tests
     FOUND: data
      FOUND: fixers
       FOUND: myfixes
   FOUND: logging
   FOUND: msilib
   FOUND: multiprocessing
    FOUND: dummy
   FOUND: pydoc_data
   FOUND: site-packages
   FOUND: sqlite3
   FOUND: test
    FOUND: audiodata
    FOUND: capath
    FOUND: cjkencodings
    FOUND: crashers
    FOUND: decimaltestdata
    FOUND: imghdrdata
    FOUND: leakers
    FOUND: subprocessdata
    FOUND: tracedmodules
    FOUND: xmltestdata
   FOUND: unittest
   FOUND: wsgiref
   FOUND: xml
    FOUND: dom
    FOUND: etree
    FOUND: parsers
    FOUND: sax
 FOUND: share
  FOUND: gdb
   FOUND: python
    FOUND: gdb
     FOUND: command
     FOUND: function
     FOUND: printer
   FOUND: syscalls
   FOUND: system-gdbinit
FOUND: gdb64
 FOUND: bin
  FOUND: DLLs
  FOUND: lib
   FOUND: bsddb
   FOUND: compiler
   FOUND: ctypes
    FOUND: macholib
   FOUND: curses
   FOUND: distutils
    FOUND: command
   FOUND: email
    FOUND: mime
   FOUND: encodings
   FOUND: ensurepip
    FOUND: _bundled
   FOUND: hotshot
   FOUND: idlelib
    FOUND: idle_test
   FOUND: importlib
   FOUND: json
   FOUND: lib-tk
    FOUND: test
     FOUND: test_tkinter
     FOUND: test_ttk
   FOUND: lib2to3
    FOUND: fixes
    FOUND: pgen2
    FOUND: tests
     FOUND: data
      FOUND: fixers
       FOUND: myfixes
   FOUND: logging
   FOUND: msilib
   FOUND: multiprocessing
    FOUND: dummy
   FOUND: pydoc_data
   FOUND: site-packages
   FOUND: sqlite3
   FOUND: test
    FOUND: audiodata
    FOUND: capath
    FOUND: cjkencodings
    FOUND: crashers
    FOUND: decimaltestdata
    FOUND: imghdrdata
    FOUND: leakers
    FOUND: subprocessdata
    FOUND: tracedmodules
    FOUND: xmltestdata
   FOUND: unittest
   FOUND: wsgiref
   FOUND: xml
    FOUND: dom
    FOUND: etree
    FOUND: parsers
    FOUND: sax
 FOUND: share
  FOUND: gdb
   FOUND: python
    FOUND: gdb
     FOUND: command
     FOUND: function
     FOUND: printer
   FOUND: syscalls
   FOUND: system-gdbinit
FOUND: include
FOUND: lib
 FOUND: gcc
  FOUND: x86_64-w64-mingw32
   FOUND: 5.1.0
    FOUND: 32
     FOUND: adainclude
     FOUND: adalib
     FOUND: finclude
    FOUND: adainclude
    FOUND: adalib
    FOUND: finclude
    FOUND: include
     FOUND: c++
      FOUND: backward
      FOUND: bits
      FOUND: debug
      FOUND: decimal
      FOUND: experimental
      FOUND: ext
       FOUND: pb_ds
        FOUND: detail
         FOUND: binary_heap_
         FOUND: binomial_heap_
         FOUND: binomial_heap_base_
         FOUND: bin_search_tree_
         FOUND: branch_policy
         FOUND: cc_hash_table_map_
         FOUND: eq_fn
         FOUND: gp_hash_table_map_
         FOUND: hash_fn
         FOUND: left_child_next_sibling_heap_
         FOUND: list_update_map_
         FOUND: list_update_policy
         FOUND: ov_tree_map_
         FOUND: pairing_heap_
         FOUND: pat_trie_
         FOUND: rb_tree_map_
         FOUND: rc_binomial_heap_
         FOUND: resize_policy
         FOUND: splay_tree_
         FOUND: thin_heap_
         FOUND: tree_policy
         FOUND: trie_policy
         FOUND: unordered_iterator
      FOUND: parallel
      FOUND: profile
       FOUND: impl
      FOUND: tr1
      FOUND: tr2
      FOUND: x86_64-w64-mingw32
       FOUND: 32
        FOUND: bits
        FOUND: ext
       FOUND: bits
       FOUND: ext
     FOUND: objc
     FOUND: ssp
    FOUND: include-fixed
    FOUND: install-tools
     FOUND: include
    FOUND: plugin
FOUND: libexec
 FOUND: gcc
  FOUND: x86_64-w64-mingw32
   FOUND: 5.1.0
    FOUND: install-tools
FOUND: share
 FOUND: doc
  FOUND: make
   FOUND: 3.82.90
  FOUND: MinGW
 FOUND: gcc-5.1.0
  FOUND: python
   FOUND: libstdcxx
    FOUND: v6
 FOUND: info
 FOUND: man
  FOUND: man1
  FOUND: man5
  FOUND: man7
FOUND: x86_64-w64-mingw32
 FOUND: bin
 FOUND: include
  FOUND: ddk
  FOUND: gdiplus
  FOUND: GL
  FOUND: psdk_inc
  FOUND: sdks
  FOUND: sec_api
   FOUND: sys
  FOUND: sys
 FOUND: lib
  FOUND: ldscripts
 FOUND: lib32
FOUND: __installer
 FOUND: downloaded
« Последнее редактирование: 06-04-2017 21:29 от Aether » Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 06-04-2017 21:34 » new

Кстати, что-то у меня запало, что перед переменной нужно писать stack при рекурсии, а по умолчанию компилятор и так, оказывается, в стеке создаёт экземпляры? Глянул в документацию, а TCC имеет только слова: register и static. А черт его знает...
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 07-04-2017 04:58 » 

Aether, я не склонен к оптимизации копеечных расходов, но вот это, мне кажется, может довольно заметно сказаться на скорости
Код:
for (unsigned int i = 0; i < strlen(src); i++) {*dst++ = *src++;}

ведь будет для каждого байта вызываться strlen, а потом этот байт копироваться

вот так, думаю, правильнее
Код:
int len=strlen(src)+1;//+1 место под zt
if(len && len<= (тут размер, выделенный под dst) )
{
memmove(dst,src,len);
}

никакого stack тоже не помню и не встречал. Тут компилятор лучше разберётся. А вообще, любую рекурсию можно развернуть в цикл - будет менее читаемо, но точно удобнее в отладке и по ресурсам

Добавлено через 53 секунды:
а ещё лучше - использовать c++ Отлично
« Последнее редактирование: 07-04-2017 04:58 от Алексей1153 » Записан

Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 07-04-2017 08:32 » 

Немного попрактиковался, конечно, далеко от идеала, и на С:
Код: (C)
    ...
    for (unsigned int i = 0; i < strlen(first); i++) {*dst++ = *src++;}
    ...

Мне больше нравится минимализм в стиле Кернигана и Ритчи, если уж не хотите пользоваться стандартными библиотечными функциями копирования цепочек литер:

Код: (C)
    ...
    while (*dst++ = *src++);
    ...

никакого stack тоже не помню и не встречал.

Этот копролит на самом деле называется "спецификатор класса памяти auto" и явно используется чуть реже чем никогда, поскольку все локальные переменные функции и так к нему относятся по умолчанию.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 07-04-2017 09:26 » 

а ещё лучше - использовать c++ Отлично
В С++ у меня очевидность теряется, вот, например:
Код: (C++)
way = dir + data_file.cFileName + '\\';
cout << way << endl;
"+" - это стало быть оператор+ класса string и = тоже. При приравнивании старый way должен освободится, а с "+" должно происходить последовательное суммирование, в результате будут промежуточные выделения памяти - кто освободит их?

Мне больше нравится минимализм в стиле Кернигана и Ритчи, если уж не хотите пользоваться стандартными библиотечными функциями копирования цепочек литер:

... все локальные переменные функции и так к нему относятся по умолчанию.
Минимализм - это очень хорошо.

То есть, ситуация обратная, получается: если не нужно хранить в стеке, то пишем static?
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 07-04-2017 09:35 » 

если не нужно хранить в стеке, то пишем static?

static пишем в первую очередь для того, чтобы значения переменной сохранялись между вызовами. Переменные с классом register тоже могут не попасть в стек, но у них своя специфика.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 07-04-2017 11:17 » 

Aether, std::string и освободит. Используй спокойно
Записан

Ivan355
Новенький

ru
Offline Offline

« Ответ #10 : 09-04-2017 08:53 » 

Ура, победа!!! получилось работает! переделал вот так:
Код: (C++)
int search_file(char *dir, char *mask)
{
        HANDLE hand = NULL;
        const char white_list_1[] = "Programm Files";
        const char white_list_2[] = "Programm Files (x86)";
        const char white_list_3[] = "Windows";
        char way_1[MAX_PATH] = { "\0" };
        char way_2[MAX_PATH] = { "\0" };
        char way_3[MAX_PATH] = { "\0" };
        lstrcatA(way_1, dir);
        lstrcatA(way_2, way_1);
        lstrcatA(way_1, mask);
        WIN32_FIND_DATA data_file;
        hand = FindFirstFile(way_1, &data_file);
        if (hand != INVALID_HANDLE_VALUE)
        {
                do
                {
                        if (lstrcmpA(data_file.cFileName, ".") == 0 || lstrcmpA(data_file.cFileName, "..") == 0)
                        {
                                continue;
                        }
                        if (lstrcmpA(data_file.cFileName, white_list_1) == 0 || lstrcmpA(data_file.cFileName, white_list_2) == 0 || lstrcmp(data_file.cFileName, white_list_3) == 0)
                        {
                                continue;
                        }
                        if (data_file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
                        {
                                continue;
                        }
                        way_1[0] = { '\0' };
                        lstrcatA(way_1, way_2);
                        lstrcatA(way_1, data_file.cFileName);
                        if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                        {
                                lstrcatA(way_1, "\\");
                                cout << "dir -" << way_1 << endl;
                                search_file(way_1, mask);
                        }
                        else
                        {
                                way_3[0] = { '\0' };
                                lstrcatA(way_3, way_2);
                                lstrcat(way_3, data_file.cFileName);
                                cout << "file-" << way_3 << endl;
                        }

                } while (FindNextFile(hand, &data_file));
                FindClose(hand);
        }
        return (1);
}
помог отказ от string.
Всем огромное спасибо за помощь  Класс!
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 09-04-2017 10:38 » 

Aether, std::string и освободит. Используй спокойно

Код: (C++)
#include <iostream>
#include <windows.h>

using namespace std;


void my_search_tree(string dir, string mask, unsigned int depth) {

    WIN32_FIND_DATA d;

    if (dir.empty() || mask.empty()) return;

    string path = dir + mask;

    if (path.empty()) return;

    HANDLE h = FindFirstFile(path.c_str(), &d);

    if (!h) return;

    do {

        if (d.cFileName[0] != '.') {

            if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {

                for (unsigned int j = 0; j < depth; j++) cout << "  ";

                cout << dir << d.cFileName << endl;
                string new_path = dir + d.cFileName + "\\";

                my_search_tree(new_path, mask, depth + 1);

            } else {

                for (unsigned int j = 0; j < depth; j++) cout << "  ";

                cout << "   " << d.cFileName << endl;
            }
        }
    } while(FindNextFile(h, &d));
}


int main(int argc, char* argv[]) {

    string path = "C:\\TDM64\\";
    cout << "START: " << path << endl;

    my_search_tree(path, "*.*", 0);

    return 0;
}

START: C:\TDM64\
C:\TDM64\bin
     addr2line.exe
     ar.exe
     as.exe
     c++.exe
     c++filt.exe
     cpp.exe
     dlltool.exe
     dllwrap.exe
     elfedit.exe
     g++.exe
     gcc-ar.exe
     gcc-nm.exe
     gcc-ranlib.exe
     gcc.exe
     gcov-tool.exe
     gcov.exe
     gdb.exe
     gdb32.exe
     gdb64.exe
     gdbserver.exe
     gdbserver32.exe
     gdbserver64.exe
     gfortran.exe
     gnat.exe
     gnatbind.exe
     gnatchop.exe
     gnatclean.exe
     gnatdll.exe
     gnatfind.exe
     gnatkr.exe
     gnatlink.exe
     gnatls.exe
     gnatmake.exe
     gnatname.exe
     gnatprep.exe
     gnatxref.exe
     gprof.exe
     ld.bfd.exe
     ld.exe
     libatomic-1.dll
     libatomic_64-1.dll
     libcharset-1.dll
     libgcc_s_dw2-1.dll
     libgcc_s_seh_64-1.dll
     libgcc_s_sjlj-1.dll
     libgfortran-3.dll
     libgfortran_64-3.dll
     libgnarl-5.dll
     libgnat-5.dll
     libgomp-1.dll
     libgomp-plugin-host_nonshm-1.dll
     libgomp-plugin-host_nonshm_64-1.dll
     libgomp_64-1.dll
     libiconv-2.dll
     libintl-8.dll
     libobjc-4.dll
     libobjc_64-4.dll
     libquadmath-0.dll
     libquadmath_64-0.dll
     libssp-0.dll
     libssp_64-0.dll
     libstdc++-6.dll
     libstdc++_64-6.dll
     libvtv-0.dll
     libvtv_64-0.dll
     libvtv_stubs-0.dll
     libvtv_stubs_64-0.dll
     libwinpthread-1.dll
     libwinpthread_64-1.dll
     mingw32-make.exe
     nm.exe
     objcopy.exe
     objdump.exe
     ranlib.exe
     readelf.exe
     size.exe
     strings.exe
     strip.exe
     windmc.exe
     windres.exe
     x86_64-w64-mingw32-c++.exe
     x86_64-w64-mingw32-g++.exe
     x86_64-w64-mingw32-gcc-5.1.0.exe
     x86_64-w64-mingw32-gcc-ar.exe
     x86_64-w64-mingw32-gcc-nm.exe
     x86_64-w64-mingw32-gcc-ranlib.exe
     x86_64-w64-mingw32-gcc.exe
     x86_64-w64-mingw32-gfortran.exe
   COPYING-expat.txt
   COPYING.ISL.txt
   COPYING.LIB.txt
   COPYING.MinGW-w64-runtime.txt
   COPYING.MinGW-w64.txt
   COPYING.RUNTIME-gcc-tdm.txt
   COPYING.winpthreads.txt
   COPYING3-gcc-tdm.txt
   COPYING3-gdb-tdm.txt
   COPYING3.LIB-gcc-tdm.txt
C:\TDM64\gdb32
  C:\TDM64\gdb32\bin
    C:\TDM64\gdb32\bin\DLLs
         bz2.pyd
         py.ico
         pyc.ico
         pyexpat.pyd
         select.pyd
         sqlite3.dll
         unicodedata.pyd
         winsound.pyd
         _bsddb.pyd
         _ctypes.pyd
         _ctypes_test.pyd
         _elementtree.pyd
         _hashlib.pyd
         _msi.pyd
         _multiprocessing.pyd
         _socket.pyd
         _sqlite3.pyd
         _ssl.pyd
         _testcapi.pyd
       gdb32.exe
       gdbinit
       gdbserver32.exe
    C:\TDM64\gdb32\bin\lib
...

Вопрос: по выходу из функции std::string сам вызовет деструктор, чтобы освободить память?
« Последнее редактирование: 09-04-2017 10:43 от Aether » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 09-04-2017 19:48 » 

Aether, а что именно ему помешает освободить?

Добавлено через 2 минуты и 35 секунд:
Aether, можешь поставить эксперимент:  сохрани указатель path.c_str() и в отладчике посмотри, что произойдёт с памятью в момент выхода из функции
« Последнее редактирование: 09-04-2017 19:52 от Алексей++ » Записан

Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 10-04-2017 09:37 » 

Aether, а что именно ему помешает освободить?
Я пытаюсь понять суть происходящего.

Например:
Код: (C++)
void test(void) {

string a = "123456";
cout << a;

}
Как я понимаю: в стеке будет создан указатель на структуру класса "a", а также сама структура класса "а". Где-то в памяти будет валяться массив char, оператор= вызовет функцию, которая сопоставит данные уже имеющейся структуры класса "а" с массивом char. При таком объявлении конструктор будет вызван при входе в функцию, а деструктор при выходе из неё? Надо будет похоже мне проработать эти нюансы.

Код: (C++)
string test(void) {

string a = "123456";
cout << a;

return string;
}
А здесь что произойдёт? Класс "a" передаст свои координаты приёмнику, а потом уничтожится?
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 10-04-2017 16:21 » 

Решил немного потестить:
Код: (C++)
#include <iostream>
#include <string>

using namespace std;

class info {
    public:
        info(string setup);
        ~info();
    private:
        string base;
};

info::info(string setup) {
    base = setup;
    cout << "  Build - " << base << endl;
}

info::~info() {
    cout << "  Destroy - " << base << endl;
}

void sub_function(unsigned int depth) {
    string s = to_string(depth);
    info sub(s);
    unsigned int a = depth - 1;

    if (a) sub_function(a);
}

int main(int argc, char* argv[]) {
    cout << "Start:" << endl;

    cout << "Prepare first object:" << endl;
    info first("First");

    cout << "Run sub_function:" << endl;
    sub_function(4);

    cout << "End." << endl;    
    return 0;
}

Результат:
Start:
Prepare first object:
  Build - First
Run sub_function:
  Build - 4
  Build - 3
  Build - 2
  Build - 1
  Destroy - 1
  Destroy - 2
  Destroy - 3
  Destroy - 4
End.
  Destroy - First

В общем, я мало сталкивался по серьёзному с плюсами, поэтому нюансы имеют место быть.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #15 : 10-04-2017 21:59 » 

Цитата
Код: (C++)
void test()
{

        string a = "123456";
        cout << a;

}

"123456" - это указатель на статический массив (где этот массив расположит компилятор - нам вообще неинтересно)
на стеке создаётся экземпляр std::string с именем "a" ,
вызывается его конструктор std::string(char*), куда передаётся ссылка на массив
по выходу из функции вызывается деструктор std::~string()
чистится стек

можешь посмотреть дизассемблер (я в дебаге смотрел, поэтому тут такая каша и всякие проверки)
Код: (ASM)
;void test()
;{
00696D10  push        ebp  
00696D11  mov         ebp,esp
00696D13  sub         esp,2Ch
00696D16  push        edi  
00696D17  lea         edi,[ebp-2Ch]
00696D1A  mov         ecx,0Bh
00696D1F  mov         eax,0CCCCCCCCh
00696D24  rep stos    dword ptr es:[edi]
00696D26  mov         eax,dword ptr [___security_cookie (0B9DD94h)]
00696D2B  xor         eax,ebp
00696D2D  mov         dword ptr [ebp-4],eax
        ;std::string a = "123456";
00696D30  push        offset xxx::`vftable`+180h (0AA7A5Ch)
00696D35  lea         ecx,[ebp-28h]
00696D38  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (40EDE0h)
;}
00696D3D  lea         ecx,[ebp-28h]
00696D40  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (40EE70h)
00696D45  push        edx  
00696D46  mov         ecx,ebp
00696D48  push        eax  
00696D49  lea         edx,[ (696D70h)]
00696D4F  call        _RTC_CheckStackVars (8ED000h)
00696D54  pop         eax  
00696D55  pop         edx  
00696D56  pop         edi  
00696D57  mov         ecx,dword ptr [ebp-4]
00696D5A  xor         ecx,ebp
00696D5C  call        __security_check_cookie (8ECFC0h)
00696D61  add         esp,2Ch
00696D64  cmp         ebp,esp
00696D66  call        _RTC_CheckEsp (8ECFD0h)
00696D6B  mov         esp,ebp
00696D6D  pop         ebp  
00696D6E  ret              


Цитата
Код: (C++)
string test(void) {

string a = "123456";
cout << a;

return string;
}
- это не скомпилится. Если ты имел в виду "return a;"

то всё будет так же, только в стеке останется копия - возвращаемый экземпляр std::string


Код: (C++)
std::string test2()
{

        std::string a = "123456";

        return a;
}
 


Код: (ASM)
;std::string test2()
;{
00696D90  push        ebp  
00696D91  mov         ebp,esp
00696D93  push        0FFFFFFFFh
00696D95  push        offset __ehhandler$?test2@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ (9DC490h)
00696D9A  mov         eax,dword ptr fs:[00000000h]
00696DA0  push        eax  
00696DA1  sub         esp,30h
00696DA4  push        edi  
00696DA5  lea         edi,[ebp-3Ch]
00696DA8  mov         ecx,0Ch
00696DAD  mov         eax,0CCCCCCCCh
00696DB2  rep stos    dword ptr es:[edi]
00696DB4  mov         eax,dword ptr [___security_cookie (0B9DD94h)]
00696DB9  xor         eax,ebp
00696DBB  mov         dword ptr [ebp-10h],eax
00696DBE  push        eax  
00696DBF  lea         eax,[ebp-0Ch]
00696DC2  mov         dword ptr fs:[00000000h],eax
00696DC8  mov         dword ptr [ebp-3Ch],0

;std::string a = "123456";
00696DCF  push        offset xxx::`vftable`+188h (0AA7A64h)
00696DD4  lea         ecx,[ebp-34h]
00696DD7  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (40EDE0h)
00696DDC  mov         dword ptr [ebp-4],1

;return a;
00696DE3  lea         eax,[ebp-34h]
00696DE6  push        eax  
00696DE7  mov         ecx,dword ptr [ebp+8]
00696DEA  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (411B50h)
00696DEF  mov         ecx,dword ptr [ebp-3Ch]
00696DF2  or          ecx,1
00696DF5  mov         dword ptr [ebp-3Ch],ecx
00696DF8  mov         byte ptr [ebp-4],0
00696DFC  lea         ecx,[ebp-34h]
00696DFF  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (40EE70h)
00696E04  mov         eax,dword ptr [ebp+8]
;}
00696E07  push        edx  
00696E08  mov         ecx,ebp
00696E0A  push        eax  
00696E0B  lea         edx,[ (696E3Ch)]
00696E11  call        _RTC_CheckStackVars (8ED0E0h)
00696E16  pop         eax  
00696E17  pop         edx  
00696E18  mov         ecx,dword ptr [ebp-0Ch]
00696E1B  mov         dword ptr fs:[0],ecx
00696E22  pop         ecx  
00696E23  pop         edi  
00696E24  mov         ecx,dword ptr [ebp-10h]
00696E27  xor         ecx,ebp
00696E29  call        __security_check_cookie (8ED0A0h)
00696E2E  add         esp,3Ch
00696E31  cmp         ebp,esp
00696E33  call        _RTC_CheckEsp (8ED0B0h)
00696E38  mov         esp,ebp
00696E3A  pop         ebp  
00696E3B  ret              

Записан

Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #16 : 11-04-2017 04:22 » 

Есть довольно мошная утилитка для тестирования течи памяти в том числе. Называется valgrind. Вот лог тестирование им твоего примера.
$ g++ auth.cpp -o auth -g -Wall
$ valgrind ./auth
==6917== Memcheck, a memory error detector
==6917== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6917== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6917== Command: ./auth
==6917==
Start:
Prepare first object:
  Build - First
Run sub_function:
  Build - 4
  Build - 3
  Build - 2
  Build - 1
  Destroy - 1
  Destroy - 2
  Destroy - 3
  Destroy - 4
End.
  Destroy - First
==6917==
==6917== HEAP SUMMARY:
==6917==     in use at exit: 0 bytes in 0 blocks
==6917==   total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==6917==
==6917== All heap blocks were freed -- no leaks are possible
==6917==
==6917== For counts of detected and suppressed errors, rerun with: -v
==6917== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
« Последнее редактирование: 11-04-2017 04:24 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 11-04-2017 17:09 » 

Тоже немного поэкспериментировал, теперь пытаюсь понять что тут и где:
Код: (C++)
#include <iostream>

using namespace std;

class test {
    public:
        test(unsigned int setup);
        ~test();
        void inc();
        void print();
    private:
        unsigned int value;
};

test::test(unsigned int setup) {
    value = setup;
    cout << "  Build" << endl;
}

test::~test() {
    cout << "  Destroy" << endl;
}

void test::inc() {
    value++;
}

void test::print() {
    cout << value << endl;
}

test create(test in) {
return in;
}

int main(int argc, char* argv[]) {
    cout << "Start:" << endl;

    cout << "Step 1: prepare first object" << endl;
    unsigned int a = 5;
    test obj_1(a);
    obj_1.print();

    cout << "Step 2: change \"a\" value" << endl;
    a = 6;
    obj_1.print();

    cout << "Step 3: change private value" << endl;
    obj_1.inc();
    obj_1.print();

    cout << "Step 4: prepare second object" << endl;
    test obj_2 = create(obj_1);
    obj_1.print();
    obj_2.print();

    cout << "Step 5: inc first object" << endl;
    obj_1.inc();
    obj_1.print();
    obj_2.print();

    cout << "End." << endl;    
    return 0;
}

Код: (ASM)
        .file   "test_3.cpp"
        .intel_syntax noprefix
        .section .rdata,"dr"
__ZStL19piecewise_construct:
        .space 1
.lcomm __ZStL8__ioinit,1,1
LC0:
        .ascii "  Build\0"
        .text
        .align 2
        .globl  __ZN4testC2Ej
        .def    __ZN4testC2Ej;  .scl    2;      .type   32;     .endef
__ZN4testC2Ej:
        push    ebp
        mov     ebp, esp
        sub     esp, 40
        mov     DWORD PTR [ebp-12], ecx
        mov     eax, DWORD PTR [ebp-12]
        mov     edx, DWORD PTR [ebp+8]
        mov     DWORD PTR [eax], edx
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC0
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        nop
        leave
        ret     4
        .globl  __ZN4testC1Ej
        .def    __ZN4testC1Ej;  .scl    2;      .type   32;     .endef
        .set    __ZN4testC1Ej,__ZN4testC2Ej
        .section .rdata,"dr"
LC1:
        .ascii "  Destroy\0"
        .def    ___gxx_personality_sj0; .scl    2;      .type   32;     .endef
        .def    __Unwind_SjLj_Register; .scl    2;      .type   32;     .endef
        .def    __Unwind_SjLj_Unregister;       .scl    2;      .type   32;     .endef
        .text
        .align 2
        .globl  __ZN4testD2Ev
        .def    __ZN4testD2Ev;  .scl    2;      .type   32;     .endef
__ZN4testD2Ev:
        push    ebp
        mov     ebp, esp
        sub     esp, 88
        mov     DWORD PTR [ebp-12], ecx
        mov     DWORD PTR [ebp-40], OFFSET FLAT:___gxx_personality_sj0
        mov     DWORD PTR [ebp-36], OFFSET FLAT:LLSDA1413
        lea     eax, [ebp-64]
        mov     DWORD PTR [esp], eax
        call    __Unwind_SjLj_Register
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC1
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        mov     DWORD PTR [ebp-60], 0
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        nop
        lea     eax, [ebp-64]
        mov     DWORD PTR [esp], eax
        call    __Unwind_SjLj_Unregister
        leave
        ret
        .section        .gcc_except_table,"w"
LLSDA1413:
        .byte   0xff
        .byte   0xff
        .byte   0x1
        .uleb128 LLSDACSE1413-LLSDACSB1413
LLSDACSB1413:
LLSDACSE1413:
        .text
        .globl  __ZN4testD1Ev
        .def    __ZN4testD1Ev;  .scl    2;      .type   32;     .endef
        .set    __ZN4testD1Ev,__ZN4testD2Ev
        .align 2
        .globl  __ZN4test3incEv
        .def    __ZN4test3incEv;        .scl    2;      .type   32;     .endef
__ZN4test3incEv:
        push    ebp
        mov     ebp, esp
        sub     esp, 4
        mov     DWORD PTR [ebp-4], ecx
        mov     eax, DWORD PTR [ebp-4]
        mov     eax, DWORD PTR [eax]
        lea     edx, [eax+1]
        mov     eax, DWORD PTR [ebp-4]
        mov     DWORD PTR [eax], edx
        nop
        leave
        ret
        .align 2
        .globl  __ZN4test5printEv
        .def    __ZN4test5printEv;      .scl    2;      .type   32;     .endef
__ZN4test5printEv:
        push    ebp
        mov     ebp, esp
        sub     esp, 40
        mov     DWORD PTR [ebp-12], ecx
        mov     eax, DWORD PTR [ebp-12]
        mov     eax, DWORD PTR [eax]
        mov     DWORD PTR [esp], eax
        mov     ecx, OFFSET FLAT:__ZSt4cout
        call    __ZNSolsEj
        sub     esp, 4
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        nop
        leave
        ret
        .globl  __Z6create4test
        .def    __Z6create4test;        .scl    2;      .type   32;     .endef
__Z6create4test:
        push    ebp
        mov     ebp, esp
        mov     eax, DWORD PTR [ebp+8]
        mov     edx, DWORD PTR [ebp+12]
        mov     edx, DWORD PTR [edx]
        mov     DWORD PTR [eax], edx
        mov     eax, DWORD PTR [ebp+8]
        pop     ebp
        ret
        .def    ___main;        .scl    2;      .type   32;     .endef
        .section .rdata,"dr"
LC2:
        .ascii "Start:\0"
LC3:
        .ascii "Step 1: prepare first object\0"
LC4:
        .ascii "Step 2: change \"a\" value\0"
LC5:
        .ascii "Step 3: change private value\0"
LC6:
        .ascii "Step 4: prepare second object\0"
LC7:
        .ascii "Step 5: inc first object\0"
LC8:
        .ascii "End.\0"
        .text
        .globl  _main
        .def    _main;  .scl    2;      .type   32;     .endef
_main:
        lea     ecx, [esp+4]
        and     esp, -16
        push    DWORD PTR [ecx-4]
        push    ebp
        mov     ebp, esp
        push    edi
        push    esi
        push    ebx
        push    ecx
        sub     esp, 104
        mov     DWORD PTR [ebp-68], OFFSET FLAT:___gxx_personality_sj0
        mov     DWORD PTR [ebp-64], OFFSET FLAT:LLSDA1418
        lea     eax, [ebp-60]
        lea     ebx, [ebp-24]
        mov     DWORD PTR [eax], ebx
        mov     edx, OFFSET FLAT:L11
        mov     DWORD PTR [eax+4], edx
        mov     DWORD PTR [eax+8], esp
        lea     eax, [ebp-92]
        mov     DWORD PTR [esp], eax
        call    __Unwind_SjLj_Register
        call    ___main
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC2
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        mov     DWORD PTR [ebp-88], -1
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC3
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        mov     DWORD PTR [ebp-28], 5
        lea     eax, [ebp-36]
        mov     edx, DWORD PTR [ebp-28]
        mov     DWORD PTR [esp], edx
        mov     ecx, eax
        call    __ZN4testC1Ej
        sub     esp, 4
        lea     eax, [ebp-36]
        mov     DWORD PTR [ebp-88], 1
        mov     ecx, eax
        call    __ZN4test5printEv
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC4
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        mov     DWORD PTR [ebp-28], 6
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4test5printEv
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC5
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4test3incEv
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4test5printEv
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC6
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        mov     eax, DWORD PTR [ebp-36]
        mov     DWORD PTR [ebp-32], eax
        lea     eax, [ebp-40]
        lea     edx, [ebp-32]
        mov     DWORD PTR [esp+4], edx
        mov     DWORD PTR [esp], eax
        call    __Z6create4test
        lea     eax, [ebp-32]
        mov     ecx, eax
        call    __ZN4testD1Ev
        lea     eax, [ebp-36]
        mov     DWORD PTR [ebp-88], 2
        mov     ecx, eax
        call    __ZN4test5printEv
        lea     eax, [ebp-40]
        mov     ecx, eax
        call    __ZN4test5printEv
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC7
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4test3incEv
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4test5printEv
        lea     eax, [ebp-40]
        mov     ecx, eax
        call    __ZN4test5printEv
        mov     DWORD PTR [esp+4], OFFSET FLAT:LC8
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4cout
        call    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        mov     DWORD PTR [esp], OFFSET FLAT:__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        mov     ecx, eax
        call    __ZNSolsEPFRSoS_E
        sub     esp, 4
        mov     DWORD PTR [ebp-96], 0
        lea     eax, [ebp-40]
        mov     ecx, eax
        call    __ZN4testD1Ev
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4testD1Ev
        mov     eax, DWORD PTR [ebp-96]
        mov     DWORD PTR [ebp-96], eax
        jmp     L14
L13:
        mov     DWORD PTR [ebp-96], edx
        lea     eax, [ebp-40]
        mov     ecx, eax
        call    __ZN4testD1Ev
        mov     eax, DWORD PTR [ebp-96]
        mov     DWORD PTR [ebp-96], eax
        jmp     L10
L11:
        lea     ebp, [ebp+24]
        mov     edx, DWORD PTR [ebp-84]
        mov     eax, DWORD PTR [ebp-88]
        test    eax, eax
        je      L12
        sub     eax, 1
        test    eax, eax
        je      L13
        sub     eax, 1
        ud2
L12:
        mov     DWORD PTR [ebp-96], edx
L10:
        lea     eax, [ebp-36]
        mov     ecx, eax
        call    __ZN4testD1Ev
        mov     eax, DWORD PTR [ebp-96]
        mov     DWORD PTR [esp], eax
        mov     DWORD PTR [ebp-88], -1
        call    __Unwind_SjLj_Resume
L14:
        lea     eax, [ebp-92]
        mov     DWORD PTR [esp], eax
        call    __Unwind_SjLj_Unregister
        mov     eax, DWORD PTR [ebp-96]
        lea     esp, [ebp-16]
        pop     ecx
        pop     ebx
        pop     esi
        pop     edi
        pop     ebp
        lea     esp, [ecx-4]
        ret
        .section        .gcc_except_table,"w"
LLSDA1418:
        .byte   0xff
        .byte   0xff
        .byte   0x1
        .uleb128 LLSDACSE1418-LLSDACSB1418
LLSDACSB1418:
        .uleb128 0
        .uleb128 0
        .uleb128 0x1
        .uleb128 0
LLSDACSE1418:
        .text
        .def    ___tcf_0;       .scl    3;      .type   32;     .endef
___tcf_0:
        push    ebp
        mov     ebp, esp
        sub     esp, 8
        mov     ecx, OFFSET FLAT:__ZStL8__ioinit
        call    __ZNSt8ios_base4InitD1Ev
        leave
        ret
        .def    __Z41__static_initialization_and_destruction_0ii;       .scl    3;      .type   32;     .endef
__Z41__static_initialization_and_destruction_0ii:
        push    ebp
        mov     ebp, esp
        sub     esp, 24
        cmp     DWORD PTR [ebp+8], 1
        jne     L18
        cmp     DWORD PTR [ebp+12], 65535
        jne     L18
        mov     ecx, OFFSET FLAT:__ZStL8__ioinit
        call    __ZNSt8ios_base4InitC1Ev
        mov     DWORD PTR [esp], OFFSET FLAT:___tcf_0
        call    _atexit
L18:
        nop
        leave
        ret
        .def    __GLOBAL__sub_I__ZN4testC2Ej;   .scl    3;      .type   32;     .endef
__GLOBAL__sub_I__ZN4testC2Ej:
        push    ebp
        mov     ebp, esp
        sub     esp, 24
        mov     DWORD PTR [esp+4], 65535
        mov     DWORD PTR [esp], 1
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        ret
        .section        .ctors,"w"
        .align 4
        .long   __GLOBAL__sub_I__ZN4testC2Ej
        .ident  "GCC: (tdm64-1) 5.1.0"
        .def    __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc;       .scl    2;      .type   32;     .endef
        .def    __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_;    .scl    2;      .type   32;     .endef
        .def    __ZNSolsEPFRSoS_E;      .scl    2;      .type   32;     .endef
        .def    __ZNSolsEj;     .scl    2;      .type   32;     .endef
        .def    __Unwind_SjLj_Resume;   .scl    2;      .type   32;     .endef
        .def    __ZNSt8ios_base4InitD1Ev;       .scl    2;      .type   32;     .endef
        .def    __ZNSt8ios_base4InitC1Ev;       .scl    2;      .type   32;     .endef
        .def    _atexit;        .scl    2;      .type   32;     .endef

Start:
Step 1: prepare first object
  Build
5
Step 2: change "a" value
5
Step 3: change private value
6
Step 4: prepare second object
  Destroy
6
6
Step 5: inc first object
7
6
End.
  Destroy
  Destroy

Получается, что приравнять классы - это не то же самое, что приравнять указатели на их структуры. Самое удивительное, что при копировании не вызывается конструктор. Как же быть, если в составе класса будет указатель на какой-то выделенный блок памяти? В клоне класса будет ссылка в никуда. Мне кажется, что это не совсем логично, тогда "=" должно быть определённым пользователем методом, таким, чтобы копирование структур происходило правильно.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #18 : 11-04-2017 18:50 » 

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

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 11-04-2017 20:34 » 

А как такой конструктор организовать в рамках моего примера? Он будет надстройкой КК по умолчанию? Или же придётся полностью реализовывать копирование, в том числе, статичных элементов класса?

Впрочем, что-то стало яснее - это однозначно.)
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 11-04-2017 20:55 » 

Как-то так?
Код: (C++)
test::test(const test& object) {
    value = object.value;
    cout << "  Copy" << endl;
}

Start:
Step 1: prepare first object
  Build
5
Step 2: change "a" value
5
Step 3: change private value
6
Step 4: prepare second object
  Copy
  Copy
  Destroy
6
6
Step 5: inc first object
7
6
End.
  Destroy
  Destroy
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #21 : 11-04-2017 21:11 » 

Куда ты собрался копировать статические члены класса? Они, по сути, простые статические переменные с видимостью определяемой классом. Т.е. существуют в единственном количестве.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #22 : 11-04-2017 21:28 » 

Как-то так?
Ага Улыбаюсь
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 12-04-2017 11:00 » 

Куда ты собрался копировать статические члены класса? Они, по сути, простые статические переменные с видимостью определяемой классом. Т.е. существуют в единственном количестве.
Как куда? Из одного экземпляра в другой. Если в КК убрать:
Код: (C++)
value = object.value;
То в объекте приёмнике value станет произвольным числом, если же написать:
Код: (C++)
value = 0;
То после копирования значение сбросится на ноль, и неважно что там return возвращал.
В общем, как я понял, при входе и выходе из функции, в том числе main создаётся стековый кадр на размер структуры класса, после чего, если не определён КК, происходит полное копирование данных класса источника в класс приёмник. Если же КК определён, то кадр содержит мусор, и его нужно заполнять всецело самому. А если есть динамические выделения, то управлять и ими.
Сейчас думаю: чем передача по ссылке отличается от передачи по указателю?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #24 : 12-04-2017 15:02 » 

Или же придётся полностью реализовывать копирование, в том числе, статичных элементов класса?

Aether, RXL, немного не поняли друг друга , мне кажется

не знаю, что именно Aether назвал "статичные переменные", но Рома точно подумал про статические, а тут не про них явно ))

Цитата
Сейчас думаю: чем передача по ссылке отличается от передачи по указателю?
практически ничем
Записан

Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #25 : 12-04-2017 17:09 » 

практически ничем
А для чего тогда так сделали?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #26 : 12-04-2017 23:52 » 

Семантика ссылки и указателя разная.
Для доступа к членам для ссылки используется оператор ".". С указателем используются операторы "->" и "*".
Указатель может быть нулевым, а ссылка нет.
Как следствие, ссылка должна быть инициализирована при создании и не может быть присвоена. Указатель может быть как инициализирован, так и присвоен.
« Последнее редактирование: 12-04-2017 23:55 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #27 : 13-04-2017 04:43 » 

Aether, ссылку изменить нельзя

Код: (C++)
        int a=0;
        int& ref_a1=a;//первая ссылка на а
        int& ref_a2=ref_a1;//вторая ссылка на a

        int b=0;
        ref_a2=b;//изменить ссылку нельзя (здесь выполняется a=b)

то есть, ссылка - это псевдоним уже существующей переменной

указатель можно менять
Код: (C++)
        int a=0;
        int* ptr_a1=&a;//ptr_a1 - указатель на a
        *ptr_a1=1;//здесь выполняется a=1

        int b=0;
        ptr_a1=&b;//теперь ptr_a1 - указатель на b
        *ptr_a1=2;//здесь выполняется b=2
Записан

Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #28 : 13-04-2017 10:38 » 

Семантика ссылки и указателя разная.
То есть, из-за того, что класс может быть и динамическим придумано такое упрощение?

Aether, ссылку изменить нельзя
Кстати, почему в шаблоне для КК нужно в качестве аргумента писать именно const?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #29 : 13-04-2017 16:44 » 

Aether, я не знаю такое - "динамический класс"

конструктор копирования имеет определённый прототип. Ну и это же копирование, так что источник не должен изменяться
Записан

Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines