Ответы пользователя по тегу C++
  • Перегрузка функций с unsigned параметром и обычным?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Все верно, по умолчанию целочисленные константы имеют тип int.
    unetway.com/tutorial/c-konstanty-i-literaly
    Ответ написан
    Комментировать
  • Сколько раз выделяется память под локальные переменные цикла в С++?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    for (int i = 0, j = 10; i < j; ++i, --j)
    {
       const int l = a[i] + 1;
       const int r = a[j] + 1;
       const std::string msg = std::to_string(l + r) + " bottles of rum";
       std::cout << msg << std::endl; 
    }

    1) i, j обьявлены в заголовке цикла. Они создаются 1 раз и живут до конца цикла.
    2) l, r обьявлены в теле цикла. Каждую итерацию мы присваиваем им нове значение. Поскольку int это базовый тип, переменная просто записывется на стек без дополнительного выделения памяти.
    3) msg это уже переменная более сложного типа. Хотя она и создается на стеке, внутри конструктора она может выделять память с помощью new. И это будет происходить на каждой итерации.
    4) Более того, std::to_string(l + r) создаст временный объект std::string, который удалится после завершения operator+

    С одной стороны полезно понимать какие операции могут приводить к выделению памяти, так как это не быстро. С другой об этом можно не думать слишком много при написании бизнес кода. Преждевременная оптимизация это не есть хорошо.
    Оптимизации компилятора работают достаточно хорошо. Но они не всесильны, и не должны менять поведение. Поэтому, содавать тяжелый обьект в цикле, если можно сделать это один раз, не очень хорошая идея.
    Ответ написан
    2 комментария
  • Как в моём коде можно реализовать сортировку и поиск по “степени риска”?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    1. Функция сортировки из стандартной библиотеки: https://en.cppreference.com/w/cpp/algorithm/sort. Обратите пример с lambda функцией. В вашем случае ее параметры будут указатели на Derivativ, и в теле будет сравнение по соответствующему свойству.
    2. У обычного массива нет begin() и end(). Используйте vector вместо массива или https://en.cppreference.com/w/cpp/iterator/begin
    3. Массив со страховками у вас создается только если выбрана 1. Немного логичнее если он будет жить все время работы программы.
    4. Сортировка меняет массив. Вероятно "2" должна создавать копию массива, сортировать его и печатать.
    5. Используйте std::string для хранения строк. Жить станет немного проще и веселее.
    5. Derivative Это что-то производное от чего-то. А у вас наоборот от него производят. Insurance или BaseInsurance более подходящее имя.
    Ответ написан
    Комментировать
  • Ошибки в программе, проблема в структуре?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Скорее с тем что пропущены многие #include. Не то что-бы тут что-то одно.
    Например в UserDB.h используется класс User, который описан в Auth.h. #include "Auth.h" исправит первую ошибку.
    Там где используется string тоже должен быть #include . Причем нельзя просто так опускать имя неймспейса
    std::
    Короче код не дописан.
    Ответ написан
    Комментировать
  • Вопрос по указателям в С++. Переменная присваимая указателю всегда в коде будет идти "&Переменная" ??

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    & перед переменной это взяте адреса.
    Аналогия с адресом как с координатами физического обьекта работает достаточно хорошо. Вы можете записать координаты на листе бумаги и получите "указатель". Если вы запишете координаты места где храните первый лист, то вы получите указатель на указатель. Чтобы просто скопировать указатель не нужно брать его адрес.
    int apple = 1;
    int* poinerToApple = &apple;
    //просто скопируем указатель
    int* poinerToApple2 = poinerToApple;
    //ожидаемо оба указывают на одно значение
    //assert покажет что условие верно
    assert(*PointerToApple == *PointerToApple2); 
    assert(*PointerToApple == apple);
    assert(*PointerToApple2 == apple);
    
    
    //так получим указатель на указатель
    int** poinerToPointerToApple = &poinerToApple;
    int** poinerToPointerToApple2 = &poinerToApple2;
    
    //разные указатели имеют разные адреса
    assert(poinerToPointerToApple2 != poinerToPointerToApple);
    //но они могут указывать на один и тот же указатель
    assert(*poinerToPointerToApple2 == *poinerToPointerToApple);
    //и по ним мы можем добраться до исходного значения
    assert(**poinerToPointerToApple2 == apple);


    Вызвать переменную в общем случае нельзя. Вызвать можно функцию f() и некоторые специальные обьекты. Вы описали вывод в консоль.
    int x = 5;
    cout << x; //напечатает 5
    cout << &x; //напечатает что-то типа 0x7fffffffd2e4
    Ответ написан
    Комментировать
  • Как сделать входную точку в DLL?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Кажется dllmain это то что вам нужно.
    Пример использования: https://stackoverflow.com/a/14273614
    Для shared libraries под Linux аналог attribute__((constructor))
    Ответ написан
    Комментировать
  • Будет ли удалён std::move?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    В С++ 20 этого точно не будет. Более того и в планах такого я не видел. Проблема в том, что move (семантика, а не сама команда) это не оптимизация, а принципиально другая операция. Оптимизация отличается тем, что она не меняет поведение (на самом делле не всегда, но в большинстве случаев). Нам может быть важен тот факт, что то место откуда мы сделали move станет пустым. Но при обычно присваивании это не так.
    В тех местах, где это можно делать автоматически, оно и так работает. RVO, NRVO оптимизации для возврата значений. Да и временные объекты по определению не требуют явного использования move.
    Ответ написан
    Комментировать
  • CodeRunner в VS Code выдает ошибку?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    VS code это умный текстовый редактор. Он может только запускать сторонние программы для сборки вашего кода, но не собирать его самостоятельно. Так делать можно, но сложно. В вашем случае он пытается запустить python, а это другой язык программирования.
    Проще всего для Win использовать Visual Studio Community.
    Ответ написан
  • Что использовать, size_t или int в цикле for?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Используйте решения в следующем приоритете:
    1. готовый stl algorithm (например std::find, std::remove_if,...)
    2. range based for "for (const auto& elem : myArray)"
    3. for (auto iter = myArray.begin()...
    4. int
    5. size_t

    Основная проблема с int -- раздражающий варнинг про сравнение знаковых и беззнаковых типов в
    i < array.size(). Немного поможет std::ssize из C++20, который возвращает int. Массивы размера больше чем int встречаются слишком редко чтобы выбирать решение по умолчанию основываясь на них.

    Беззнаковые типы приводят к куче ошибок связаных с отрицательными числами. В идеале их нужно использовать только там где нужны контролируемые переполнения (операции по модулю 2^{32,64}). Простой пример где можно выстрелить себе в ногу это цикл от 10 до 0.
    Ответ написан
    Комментировать
  • Как удалить элемент массива?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto iterToRemove = std::next(a, 4);
    std::copy(std::next(iterToRemove), std::end(a), iterToRemove);


    UPD:
    Нужно понимать, что поскольку мы не уменьшаем размер, в конце массива будет "мусор", а именно копия последнего элемента.
    Ответ написан
  • Как распределять свои проекты?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Используйте cmake.
    Ответ написан
    Комментировать
  • С ++. Создание и запись бинарного файла?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Для типов, где важен размер желательно использовать fixed width типы.
    Заполнять можно из текстового файла собственного формата или одного из стандартных: ini, json, yaml. Во втором случае стоит воспользоваться готовой библиотекой для чтения файлов соответствующего формата.
    Так же можно написть GUI, но это отдельная история.
    Ответ написан
    Комментировать
  • Почему sizeof показывает фактический размер массива хотя по сути имя массива это указатель на первый элемент?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    По сути статический массив это действительно указатель. Но реально тип другой и компилятор знает реальный размер массива. После того как вы приводите массив к типу указателя (например при передаче в функцию), эта информация теряется и sizeof уже вернет размер указателя.
    Ответ написан
    2 комментария
  • Как понять, где ссылка и где копия?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    С управляемой кучей я все понял, еще я не могу понять, как можно вернуть псевдоним (ссылку) на тип, который размещается не в управляемой куче и вообще почему на него можно создать указатель

    На самом деле разница между "кучей" и "не кучей" не такая и большая с точки зрения указателей.
    У нас есть 3 варианта размещения переменных:
    1. Куча. int* a = new int(3);
    2. Стек. int b = 5;
    3. Константная память, инициализируемая на старте приложения. char* c = "hello world";


    С точки зрения процесса есть большой непрерывный кусок памяти, который называется виртуальная память.
    Куча это кусок этой памяти, который хранит сами данные плюс некоторую служебную информацию, которая позволяет например находить свободные места в памяти.
    Стек это другой кусок, для которого дополнительно хранится указатель на "голову", который мы сдвигаем при push и pop. Но данные по прежнему в том же большом куске виртуальной памяти с той же адресацией.
    Константная память это третья зона с самым простым устройством. Туда записываются значения при старте программы и больше не меняются до конца ее работы.

    Также полезно понимать что ссылка и указатель это по сути одно и то же "под капотом". Просто в языке работа с ними выглядит немного по-разному. Ну и ссылка имеет меньше возможностей (а значить меньше простор для ошибки) вроде указывания в никуда (nullptr).

    Таким образом мы можем взять указатель или ссылку на переменную вне зависимости от ее местоположения. По сути это просто порядковый номер ее начала в виртуальной памяти.

    Копия это отдельный участок в памяти. Указатели на оригинал и копию будут иметь разные значения. при изменении копии оригинал не будет затронут.
    Аналогия с почтовыми адресами более чем уместна. Адрес дома записанный на бумаге - указатель. Сам дом по этому адресу - значение. Создание копии - построить такой же дом в другом месте города. Адрес у копии дома будет разумеется другой.
    Ответ написан
    2 комментария
  • Какими способами можно ускорить работу с объектами на сцене при большм удалении?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    1. Лодирование -- не показывать и не давать выделить мелкие объекты на таком масштабе.
    2. Кластеризация. Объединяем близкие объекты в группы по близости. Например так работают маркеры на яндекс картах. Если производительность упирается в обновление множества объектов, групповое изменение можно сделать асинхронным и ленивым.
    3. Можно сделать что-то среднее между 1 и 2. Если граф сцены хорошо группирует объекты логически, то можно прописать лодирование для этих узлов. Например на верхнем уровне у нас есть машина, при увеличении мы можем выделять и двигать отдельные узлы: двери, колеса...
    Ответ написан
    Комментировать
  • Как сделать перекрестные структуры?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Реализацию метода отделить, плюс передавать по константной ссылке вместо копии forInt(const forFloat& arg);
    Ответ написан
    1 комментарий
  • Где ошибка в реализации алгоритма QuickSort?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Вектор передаете по значению. При каждом вызове функции будет создаваться копия. Исправить эту ошибку так: void Quicksort(vector<int> &A, int p, int r)
    Ответ написан
  • Как правильно собрать кроссплатформенный проект?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    MyClass_L.cpp и MyClass_W.cpp нужно тоже целиком завернуть в ifdef
    Либо, что наверно более правильно, надо сказать вашей системе сборки (qmake я так понимаю), что надо собирать только нужные cpp.
    doc.qt.io/archives/qt-4.8/qmake-tutorial.html "Adding Platform-Specific Source Files"
    Ответ написан
  • Как создать дерево, каждая вершина которого содержит указатель на элемент данных void*?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Если это не лаба, которую нужно было сдать вчера, то стоит начать с чего-то более простого (в противном случае вам к фрилансерам). Возможно что-то из этого вы уже делали, но из вашего вопроса кажется, что вы не знаете с чего начать. Задание сложное для начинающего, будьте готовы потратить на него несколько дней из новогодних праздников.

    Структуры. Ключевое слово struct. Именно они будут элементами. Прочитайте про них.
    Структуры данных на указателях. Дерево -- сложная структура. Начните с односвязного списка. Примеров куча в сети. Тут вам не обойтись без функций. А еще лучше написать класс LinkedList.
    Итераторы. Когда написан список, попробуйте разобраться с итераторами. Написать итератор для списка не сложно, но тут уже нужно иметь минимальные представления о классах, методах, перегрузке операторов.
    Если сложно, то можно обойтись без них, задача не сильно пострадает.
    Деревья. После того как написан список, разобраться с деревьями будет проще. Забейте на "элемент данных void*", пусть у вас это будет то же что и в любом понравившемся примере из интернета. Тем более, в C++ стараются избегать void*.
    Обход дерева. Итераторы предполагают, что вы сможете перебирать элементы дерева в некотором порядке. В основном используют 2 подхода: обход в глубину и обход в ширину. Первый несколько проще реализовывать с помощью рекурсии. Для второго может потребоваться структура данных очередь, которую будет полезно написать на основе односвязного списка.
    Дерево поиска. Вас просят сделать так, чтобы меньшие элементы были ближе к корню дерева. Есть структура данных "куча"(обычно бинарная куча) , которая это обеспечивает. Но на практике чаще используют деревья поиска, которые тоже это гарантируют. Это достаточно непростая тема, к ней можно вернуться как закончите с остальным.
    Ответ написан
    1 комментарий
  • Как сравнить 2 вектора и удалить элементы из второго?

    tsarevfs
    @tsarevfs Куратор тега C++
    C++ developer
    Первый вариант -- просто сделать это:
    std::erase(
    	std::remove_if(myVec.begin(), myVec.end(), 
    		[&newVec](const A &a)
    		{
    			return std::find_if(newVec.begin(), newVec.end(), [&a](const A &newA){ return a.id ==  newA.id; }) == newVec.end();
    		}),
    	myVec.end());


    Для упрощения можно перегрузить оператор == для A так, чтобы он сравнивал id:
    struct A
    {
    	//...
    	bool operator==(const A &other) const
    	{
    		return a.id == other.id;
    	}
    	//...
    };
    
    std::erase(
    	std::remove_if(myVec.begin(), myVec.end(), 
    		[&newVec](const A &a)
    		{
    			return std::find(newVec.begin(), newVec.end(), a) == newVec.end();
    		}),
    	myVec.end());


    Эти решения будут пробегать по всем элементам из newVec для каждого элемента в myVec. Уже при размере в 1000 элементов для каждого, надо будет сделать 1 000 000 сравнений. ВЫход -- использовать set или unordered_set:

    namespace std
    {
    	//для unordered_set
    	template<>
    	struct hash<A>
    	{
    		std::size_t operator()(const A &a)
    		{
    			return std::hash<int>()(a.id);
    		}
    	}
    
    	//для std::set
    	template<>
    	struct less<A>
    	{
    		bool operator()(const A &lha, const A &rha)
    		{
    			return lha.id < rha.id;
    		}
    	}
    }
    
    std::unordered_set<A> newSet;
    //std::set<A> newSet
    
    newSet.insert(a);
    newSet.insert(b);
    newSet.insert(d);
    
    std::erase(
    	std::remove_if(myVec.begin(), myVec.end(), 
    		[&newSet](const A &a)
    		{
    			return newSet.find(a) == newSet.end();
    		}),
    	myVec.end());
    Ответ написан
    Комментировать