Ответы пользователя по тегу C++
  • Какое время жизни объекта в std::unique_ptr?

    @Mercury13
    Программист на «си с крестами» и не только
    Уничтоженный unique_ptr уничтожит ваш объект.

    «Уничтожит» — это значит, вызовет деструктор и сделает память доступной менеджеру памяти. Теперь другие указатели, которые смотрят на этот объект, будут «висячими», и при их разыменовании программа может сделать ЧТО УГОДНО.

    А теперь посмотрим, что именно ей угодно. Ваша функция foo() невиртуальная и не имеет дела с полями, ей нужен только this (указатель на объект), который даже не разыменовывается. Она в принципе не может вылететь, даже если десять раз занулить этот объект!

    То, что вы хотите сделать — это семантика std::shared_ptr/weak_ptr.
    std::shared_ptr<ttt> sh1 = std::make_shared<ttt>();
    std::weak_ptr<ttt> we = sh1;
    {
      std::shared_ptr<ttt> sh2 = sh1;
      sh1 = nullptr;
    }
    std::cout << we.expired();  // должно быть true


    UPD. Вот для таких, как ты, и ввели в C++14 функцию std::make_unique, по аналогии с std::make_shared. Просто чтобы было меньше таких ошибок.
    Ответ написан
    Комментировать
  • Разделение строки из символом в массив?

    @Mercury13
    Программист на «си с крестами» и не только
    // считать строчку
    std::string s;
    std::getline(std::cin, s);
    // …и разбираем её потихоньку через поток-строку
    std::istringstream is(s);
    int i;
    std::vector<int> v;
    while (is >> i)
      v.push_back(i);
    Ответ написан
    Комментировать
  • Как выделяется память в классах?

    @Mercury13
    Программист на «си с крестами» и не только
    Examp ex = new Examp ();
    Неверный код, надо Examp* ex = new Examp;

    В случае статического определения (Examp ex2;) — в той памяти, где обычно располагаются объекты. То есть:
    • Если это поле объекта — то в теле объекта, которое может быть где угодно (куча, сегмент данных, стек).
    • Если static/глобальный — то в сегменте данных.
    • Если локальный — в стеке. Конкретно тут локальная переменная, и она будет в стеке.

    В случае динамического определения (Examp* ex = new Examp;) — в «куче».
    В этом примере, кроме операции new, которая заводит объект в куче, видим ещё и указатель, который располагается «там, где обычно» — в теле объекта, сегменте данных или стеке.
    Ответ написан
    Комментировать
  • Bit shift (swap bytes) как это в действительности работает?

    @Mercury13
    Программист на «си с крестами» и не только
    Банально сначала надо unsigned value = 0;
    Вы вроде делаете полный порядок, но начальное присваивание неверное.

    UPD. Проверил в деле — так и есть.
    Ответ написан
    1 комментарий
  • Как проверить существует ли указатель или был удален?

    @Mercury13
    Программист на «си с крестами» и не только
    В Си++11 для этого есть два класса: std::shared_ptr и std::weak_ptr.

    Первый служит для того, чтобы несколько указателей «смотрели» на один объект, и при исчезновении ВСЕХ объект автоматически исчезал.

    Второй «смотрит» на тот же объект, что управляется shared_ptr’ами, но не мешает объекту удаляться. Его можно преобразовать в shared_ptr и тогда уж посмотреть, исчез объект или нет.

    UPD. Вы делаете свой shared_ptr. Тогда, если shared_ptr не NULL — значит, считаем, что объект действительно там есть! А если кто-то удалил своими силами — значит либо shared_ptr глючный, либо кто-то удалил объект в объод семантики умных указателей.

    Кроме того, код по ссылке странный. if (ref_count == 0) — это мы сравниваем указатель с NULL! Написано «переписываем оператор равенства» — по факту переписываем операцию присваивания…
    Ответ написан
    9 комментариев
  • Почему не работает (с++)?

    @Mercury13
    Программист на «си с крестами» и не только
    Надо long long n;
    Дело в банальном переполнении, но profesor08 дал явно неверный ответ.
    Ответ написан
    1 комментарий
  • Что не даёт на C++ писать кроссплатформенные приложения?

    @Mercury13
    Программист на «си с крестами» и не только
    Си — язык очень близкий к железу. Когда мы пишем на Java, мы пишем код под Java-машину. На Си мы пишем код под процессор. Главная проблема, связанная с любыми подобными языками,— отсутствие понимания целевых ОС программистами и тестирования — тестерами. Это нужно, ибо абстрагирование от машины очень тонкое.

    Поскольку перед нами очень тонкая прослойка, абстрагирующая от машины, приходится принимать меры, чтобы код переносился с машины на машину (даже с x86 на x64). Отлично это описано в блоге PVS-Studio.

    В Windows и Linux машина-то одна и та же, но конкретно в Си++ к этому добавляется устаревшая по некоторым вещам стандартная библиотека. Примеры…
    • Поддержка юникодных имён файлов пока не кроссплатформенная.
    • Унаследоваться от std::ostream — ужос такой ещё.
    • Как сконвертировать текст в UTF-8? Загугли и посмотри, какой там вавилон из шаблонов.
    Отсюда огромное количество производителезависимых расширений, чужих библиотек, повторяющих стандартную, и прочее. Важный пункт тут: чужих библиотек, повторяющих стандартную. Если у тебя строки нестандартные и файлы нестандартные — какая тут кроссплатформенность?
    Ответ написан
    Комментировать
  • Наследование оператора присваивания (=), как это сделать?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему не прописывается автоматически? А потому что в Test2 будет больше полей, и никто, кроме вас, программиста, не знает, что с ними делать.

    Но никто не мешает самому написать операцию =, например.
    class Test2 : public Test
    {
    private:
      typedef Test Super;
    public:
      Test2& operator = (const Test& x);
    };
    
    Test2& Test2::operator = (const Test& x)
    {
      Super::operator = (x);
      // придумай, что сделать с недостающими полями
      return *this;
    }
    Ответ написан
    3 комментария
  • В чем суть WinApi?

    @Mercury13
    Программист на «си с крестами» и не только
    Windows API — это самый низкоуровневый интерфейс Windows, доступный прикладному программисту — в том плане, что он на долгосрочной поддержке и не изменится с Windows 11.

    Поверх Windows API работают все BOOST и STL.

    Пример: читать файл в 130 мегабайт по одному байту. Добавив асинхронного чтения через OVERLAPPED, я сумел это сделать менее чем за 2 секунды (это был поток общего назначения с виртуальными read(), write() и seek(); специализированный прикладной буфер даст ещё выигрыша, но и это хорошо). То же самое через FILE* — не дождался.

    Пример второй, всё те же файлы. Дело в том, что Excel захватывает свои файлы на всё время, пока он открыт. Закрывать? — плохой выбор. Добавив один флажок в CreateFile, документы всё-таки стало возможным открывать при работающем Excel.
    Ответ написан
    2 комментария
  • Как передать вектор в функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Раз мы изменяем наш вектор — то по неконстантной сцылке.

    void add (int n, std::vector<int>& vec){
        vec.push_back(n);
    }
    
    std::vector <int> myVec;
    add(5, myVec);
    Ответ написан
    Комментировать
  • Какие есть библиотеки для работы с RAW изображениями?

    @Mercury13
    Программист на «си с крестами» и не только
    1. RAW есть несколько штук: RAW CHDK, CRW Canon, NEF Nikon, платформонезависимый, но мало кем используемый DNG…
    2. Если у вас графической редактор общего назначения, крайне не советую. Для «проявки» RAW нужен особый инструментарий, которого в редакторе общего назначения нет. Плюс куча очень умных вещей, вроде дебайеризатора и шумодава. Оставьте это лайтрумам!
    XnView, допустим, смотрит, но получается дрянь — в CHDK RAW все эти дебайеризации и кривые яркости сделаны как попало, и шумодава никакого. Хотя формат, признаться, редкий, Adobe его берёт только через промежуточный платформонезависимый DNG.
    В Nikon NEF, по-видимому, смотрит превьюху: нет никакой разницы с Medium JPEG — любая программа проявки хоть где-то да проявит свой характер. Впрочем, одна есть: адовы искажения, присущие пережатому JPEG. К тому же снял в ч/б — он и вывел ч/б, в отличие от DxO, которому надо ещё указать, что формат с матрицы надо ещё в ч/б конвертнуть.
    (Других фотоаппаратов у меня не было.)
    Но XnView — просмотрщик, ему позволительно, он должен поддерживать как можно больше форматов и показывать их, пускай как попало.
    Фотошоп открывает, но там этот инструментарий в каком-то виде есть, и под капотом нечто очень умное, на голову превосходящее внутрикамерную проявку мыльниц Canon (зеркалку Nikon не проверял). Но и они собрали все свои наработки по RAW и сделали отдельную программу специально для проявки цифрофото — Lightroom.
    3. Обратно в RAW в принципе не стоит. Это файл с матрицы фотоаппарата, и точка. Вы что, хотите снимки подделывать?

    UPD. Ясно, вы решили именно проявлять несколько кадров в один HDR…
    Тогда задача библиотеки — дебайеризовать, возможно, подавить шум, И ВСЁ. Вам нужны картинки в ЛИНЕЙНОМ цветовом пространстве с 16-ю битами на канал. Обычная проявка в JPEG (BMP, TIFF) НЕ КАТИТ, у них по умолчанию ГАММА-СКОРРЕКТИРОВАННОЕ пространство и единица около нуля не равна единице около 255. Скажем так: на экране, чтобы выделялось на чёрном фоне, надо осветлять почти на 60 единиц, на белом — затемнять на 16.

    Остальную магию вы уж как-то сами проведите. 1) Подправьте искажения объектива (как геометрические, так и цветовые). 2) Склейте три кадра в один с дробным цветовым пространством. 3) Придумайте, как всё это чудо свести в узкий диапазон экрана. 4) Наладить все эти гамма-коррекции и прочие кривые. 4) И только тогда преобразовать в целое [0…255].
    Ответ написан
    2 комментария
  • Не могу найти ошибку в использовании long double в C?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня всё сработало. Может, зависит от библиотеки Си? Какой компилятор?

    UPD. Сработало на MinGW.
    Ответ написан
    1 комментарий
  • Почему меняется выходное значение после нескольких запусков программы?

    @Mercury13
    Программист на «си с крестами» и не только
    Компилятор какой используете? У меня на MinGW всё постоянно — и постоянно не дробная часть. Есть две возможные причины нестабильного поведения.
    1. Флаги сопроцессора — какая-то библиотека Си их не выставляет в постоянное значение.
    2. Неопределённое поведение (uint32_t)var в предпоследней строке. Число-то >1016, а uint32 — это 4·109.

    Тут вы множите число на 10, пока оно не станет целым. Если оно не точный double (а оно не точный), получается ситуёвина, когда младшие биты зависят от флагов сопроцессора, и неизвестно, сколько итераций проработает программа. В любом случае крайне мала вероятность, что будет нечто умещающееся в uint32_t. Таким образом, есть такие варианты обойти проблему.
    1) Умножить сразу на 1e8, а затем обрезать нули.
    2) Сконвертировать в uint64_t.

    Преобразование в uint64_t даёт постоянные 28800000000000024.
    Умножение на 1e8 (число подобрано такое, чтобы в uint32_t вмещалось)
    var *= 1e8;
        number = (uint64_t)var;
    
        while (number % 10 == 0)
            number /= 10;

    даёт 288.

    UPD. Сам я для преобразования дробного в строку в коммерческой проге использую собственную функцию, основанную на GRISU. Там есть много функций наподобие: точность 7 знаков, но если число <1010 — выводим его как целое, с 9-ю знаками.
    Ответ написан
    Комментировать
  • Почему код не работает C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Этим переменным не присваивали начального значения и в них могло оказаться что угодно.

    Переводите с английского!
    Ответ написан
    8 комментариев
  • Как реализовать сумму дробей?

    @Mercury13
    Программист на «си с крестами» и не только
    Заводим структуру-сумматор. Изначально она 0/1. Что-то типа
    typedef struct {
      int num, den;
    } Fraction;
    
    …
    
    Fraction sum = { 0, 1 };

    Дальше пишу псевдокодом, НОД и НОК разберись, как реализовать самому.
    для каждой очередной дроби
      ввести(дробь)
      новыйЗнам = НОК(сумматор.знам, дробь.знам)
      множСумм = новыйЗнам / сумматор.знам
      множДробь = новыйЗнам / дробь.знам
      новыйЧисл = сумматор.числ × множСумм + дробь.числ × множДробь
      сокрНод = НОД(новыйЧисл, новыйЗнам)
      сумматор.числ = новыйЧисл/сокрНод
      сумматор.знам = новыйЗнам/сокрНод

    Можно и оптимизировать, но тогда нужна хитрая разновидность алгоритма Евклида; в учебных целях не стоит.

    И ещё. Одна из известных ошибок в написании НОК — произведение аргументов не влезает в свой тип, а НОК влезает. Поймёшь, как в такой ситуёвине избавиться от переполнения?
    Ответ написан
    Комментировать
  • Как разобратся с кодом?

    @Mercury13
    Программист на «си с крестами» и не только
    Матрица имеет вид «хребта», на котором висят массивы-строки.

    Вставка работает так.
    1. Завести новый хребет.
    2. Завести новую строку.
    3. Посадить все остальные строки на новый хребет.
    4. Перенести новую матрицу на место старой.

    Удаление работает точно так же, только без 2.

    Как избавиться от говнокода.
    1. Стоило бы разделить интерактивное удаление и собственно удаление.
    2. Стоило бы тащить this (с какой матрицей работаем). А то на данный момент работаем с одной матрицей, и точка.
    3. Если уж методы — может, стоит писать в объектном стиле?
    4. Снова-таки, утечки памяти!
    Ответ написан
  • Как передать двумерный динамический массив в другую функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть два способа наладить динамический 2D-массив: «хребет» и «линейный массив».

    Хребет определяется как int** a = new int*[m];
    А затем каждый элемент хребта присваиваете new.
    Доступ a[i][j].

    Линейный массив определяется int* a = new int[m*n];
    Доступ a[i*n + j].

    Ваш случай — линейный массив, то есть
    void func(int a[], int n, int m)
    …
    func(a[0], n, m);


    Советую как-то заинкапсулировать эти массивы и передавать
    void dumpArray(const Array2D& x)
    К сожалению, у инкапсулированного массива нет хорошего способа сделать a[i][j], но можно a(i,j).
    Ответ написан
    2 комментария
  • Можно ли вынести реализацию шаблонного класса в отдельный cpp файл?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно в таких случаях.
    1. Если у шаблона ровно N специализаций и (N+1)-й быть не может.
    2. Если он private и его синтаксически невозможно вызвать откуда-то ещё, кроме CPP.
    3. template<> (полностью специализированная функция без шаблонных параметров). Ей место именно в CPP, если она общедоступная и не inline.

    Стек, очевидно, ни к одному из этих случаев не относится.

    Код создаёт не сам шаблон, а его расшаблонивание!
    Ответ написан
    Комментировать
  • Что означают эти строки в коде?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Указатель на указатель. Мы создаём 2D-массив как кучу динамических 1D-. Если 1D-массив — указатель, то массив из таких 1D- — массив из указателей, то есть указатель на указатель.
    2. Указатель простой (создать 1D-массив из указателей, который станет «хребтом» нашего 2D-).
    Ответ написан
    5 комментариев
  • Какие dll добавить в проект Qt, чтобы на удаленном компьютере работал доступ к MySQL?

    @Mercury13
    Программист на «си с крестами» и не только
    Если с MySQL работаем напрямую, то
    plugins\sqldrivers\qsqlmysql.dll
    libmysql.dll
    Ответ написан
    4 комментария