Ответы пользователя по тегу C++
  • Почему NetBeans 8.2 подчеркивает все красным?

    @Ariox41
    Скорее всего он не нашел стандартную библиотеку. Какие ОС и компилятор?
    Ответ написан
  • Как выйти из нескольких вложенных циклов?

    @Ariox41
    Простейший способ для c++ - обернуть в лямбду и выйти через return. Аналогичный подход можно применять для инициализации переменных, но о читаемости такого кода до сих пор идут споры.

    LIMIT = ...
    matrix = ...
    count = ...
    [&]{
        for (int i = 0; i < LIMIT; i++) {
            for (int j = 0; j < LIMIT; j++){
                int value = matrix[i][j];
    
                for (int a = 0; a < LIMIT; a++) {
                    for (int b = 0; b < LIMIT; b++)  {
                        if (value == matrix[a][b]){
                            count++;
                        }
                        if (count == 2) {
                            std::cout << "Indexes of elements: " << "[" << i << ", " << j << "], ";
                            std::cout << "[" << a << ", " << b << "]" << std::endl;
    
                            return;
                        }
                    }
                }
            count = 0;
            }
        }
    }();
    Ответ написан
    Комментировать
  • Причины утечек памяии?

    @Ariox41
    В деструкторе CGamePetri ошибка:

    for( vector<CPetriAction *> :: iterator i = m_Messages.begin(); i != m_Messages.end();  )
    {
         delete *i;
         m_Messages.erase( i );
    }


    Когда вызывается erase итератор становится невалидным. На практие скорее всего удаляются элементы 0, 2, 4 ... в первой половине вектора, т.к. когда удаляется нулевой элемент - первый становится нулевым, второй первым, и итератор переходит на новый первый элемент, который раньше был вторым. Решается легко:
    for( vector<CPetriAction *> :: iterator i = m_Messages.begin(); i != m_Messages.end();  )
    {
         delete *i;
    }
    //m_Messages.clear(); // - в данном случае смысла нет, т.к. это деструктор


    Или еще проще:
    for(auto& ptr:  m_Messages){
       delete ptr;
    }


    Если в m_Messages хранить unique_ptr - тогда и этого не нужно, объекты удалятся автоматически в деструкторе вектора.
    Ответ написан
  • В чем причина ошибки компилятора "use of deleted function" в данном коде?

    @Ariox41
    Просто замените круглые скобки на фигурные в списке инициализации: пример.

    Пустой список аргументов не может быть передан в конструктор через круглые скобки - иначе это будет эквивалентно строке MyClass value(); - а это уже объявление функции. Из-за этого пустой список аргументов интерпретироваться как пустой список инициализации, но пустой список инициализации опять же нельзя передать в конструктор без аргументов, используя круглые скобки, т.к. один аргумент всё-таки есть. Но при использовании фигурных скобок список инициализации нормально вызывает конструктор без аргументов. При этом неявное преобразование из пустого списка инициализации в MyClass возможно - неявно вызывается конструктор без аргументов:
    void foo(MyType2&&){ }
    foo({}); // Компилируется

    А значит строка MyClass({}) преобразует {} во временный объектMyClass, а его попытается передать в удалённый конструктор перемещения MyClass
    Ответ написан
    Комментировать
  • Как проверить вывод на число?

    @Ariox41
    Вывод - это вывод из программы в поток (cout), ввод - это ввод из потока в программу (cin), это можно понять по названиям.

    Один из вариантов - считывать не чисто, а строку, а затем уже преобразовать строку в чисто другими функциями.
    Или можно воспользоваться интерфейсом обработки ошибок потоков:

    #include <iostream>
    #include <limits>
    
    int main() {
        int num = 0;
    
        while(num != -1) {
            std::cout << "Enter the number to push: ";
            std::cin >> num;
            if(std::cin.fail()){
                std::cout  << "It is not number" << std::endl;
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<int>::max(), '\n');
            } else{
                std::cout << "num = " << num << std::endl;
            }
        }
        
        return 0;
    }
    Ответ написан
    Комментировать
  • Как правильно передать двумерный массив в функцию?

    @Ariox41
    Можно так:

    #include <array>
    
    template<std::size_t ColumnCount, std::size_t RowCount > 
    int foo(int (&matrix)[ColumnCount][RowCount]){ 
       int r = 0;
       for(auto& row: matrix){
           for(auto& x: row)
              r += x;
       }
       return r;
    }
    
    int bar(){
        int matrix [][2] = {{1, 2}, {3, 4}, {4, 6}};
        return foo(matrix);
    }


    С-массивы в функции можно передавать только по ссылке. Или преобразовать в массив указателей.

    Вообще, для передачи С-массивов придуман std::array, но двумерный C-массив нельзя напрямую привести к std::array<std::array<int, M>, N>. Но можно изначально работать с std::array:
    template<std::size_t ColumnCount, std::size_t RowCount > 
    
    int foo(std::array<std::array<int, RowCount>, ColumnCount>& matrix){ 
       int r = 0;
       for(auto& row: matrix){
           for(auto& x: row)
              r += x;
       }
       return r;
    }
    
    int bar(){
        std::array<std::array<int, 2>, 3> matrix = {{{1, 2}, {3, 4}, {4, 6}}};
        return foo(matrix);
    }
    Ответ написан
  • Как учить C++ программисту который не учился в вузе в данной сфере?

    @Ariox41
    По стандартной библиотеке могу посоветовать "Стандартная библиотека C++. Справочное руководство". Я, правда, читал только первое издание (сейчас актуально второе), но вряд ли она стала сильно хуже. Ну и cppreference.com для изучения стандартной библиотеки тоже полезен.

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

    По остальным запросам сложнее - всё сильно зависит от текущего уровня знаний и от цели изучения. Возможно, стоит начать с книг для новичков, где объясняются основы языка (тут много вопросов про такие книги). Но наверняка большая часть изложенной в них информации вам уже знакома, при этом часто в таких книгах приводятся не лучшие способы решения задач. Шлее неплохой выбор для новичка в C++, знакомого с другими ЯП, но он всё же больше о C++ в экосистеме Qt, с точки зрения чистого C++ там хватает недостатков.

    Можно попробовать почитать Майерса ("Эффективное использование C++. 50 рекомендаций..." и/или "35 рекомендаций", не стоит начинать с последних книг). Они могут оказаться слишком сложными, но отвечают на большую часть ваших запросов (или хотя бы станет понятно, куда копать дальше и нужно ли оно вам). Там некоторые вещи однозначно будут непонятны, но при первом прочтении их можно просто пропустить - главы слабо связаны между собой. Меня в своё время книги Майерса мотивировали изучать C++ всерьёз (до этого выбирал между C++ и Java), на тот момент я знал C++ на уровне C с классами.
    Ответ написан
    4 комментария
  • Какой учебник выбрать новичку для изучения C++?

    @Ariox41
    Майерса стоит почитать однозначно, но позже, и начать лучше с "55 советов" или "35 советов" - там лучше объясняются идеи modern c++ (но старые издания я бы не стал покупать, тем более что отдельные главы из них и так растащены по множеству статей в интернете). Эти книги предназначены не для новичков, скорее они предназначены для тех, кто уверенно пишет хотя бы в стиле "C с классами" и имеет хотя бы общее представление о шаблонах. В них объясняются подходы, позволяющие улучшить читаемость кода и уменьшить дублирование.

    Книги для новичков я не читал, посоветовать не могу.
    Ответ написан
    Комментировать
  • Как правильно использовать QWidget в QML?

    @Ariox41
    В строке w = new QPushButton; не указан родитель, а значит кнопка создаётся для цикла событий основного потока. Однако QML может работать в своём собственном потоке (с которым связан свой цикл событий), из-за чего кнопка создаётся в потоке QML, но для цикла событий основного потока. Об этом и написано в сообщении об ошибке. Должна помочь передача родителя, работающего в потоке QML: w = new QPushButton(this);. При этом кнопка будет использовать цикл событий родителя (this уже от своего родителя знает, в каком он потоке).
    Ответ написан
  • Unittests в Qt, как правильно организовать структуру проекта?

    @Ariox41
    Каждый набор тестов в QTest обычно создается как отдельный подпроект (приложение). Соответственно, и запускаются тесты как отдельное приложения. Выбор текущего активного проекта для запуска в QtCreator осуществляется через панель "проекты" слева, или по "ctrl + T", это относится и к тестам. В принципе, тесты можно сосредоточить и в одном проекте, но это крайне неудобно как раз из-за проблемы, с которой вы столкнулись. Для такой конфигурации лучше подходит Catch. QtCreator вроде бы умеет запускать все тесты одновременно, но я этим не пользовался.
    Ответ написан
    Комментировать
  • Корректен ли этот код?

    @Ariox41
    В стандарте есть правило, по которому при создании константной ссылки на автоматически управляемый объект его время жизни расширяется до времени жизни константной ссылки. Однако это не относится к оператору return и есть особое правило для списков инициализации (подробнее тут). Соответственно, в следующем примере функция getRef некорректна, но функция foo реализована корректно.
    const std::string &getRef() {
        std::string tmpObject = "123";
        return tmpObject;
    }
    
    void foo(){
        const std::string& ref = getRef();
        std::cout << ref; // Выведет 123
    }


    В любом случае, использование такого подхода не имеет смысла - можно просто полагаться на оптимизацию возвращаемого значения и писать так:

    std::string getStr() {
        std::string tmpObject = "123";
        return tmpObject;
    }
    
    void foo(){
        std::string str = getStr();
        std::cout << str; // Выведет 123
    }
    
    // На крайний случай можно так - это точно корректно, но лучше не нужно - иначе кто-нибудь 
    // может случайно удалить const, что приведёт к проблемам. 
    void bar(){
        const std::string& ref = getStr();
        std::cout << ref; // Выведет 123
    }
    Ответ написан
    3 комментария
  • Java или C++ в качестве первого языка. Что выбрать?

    @Ariox41
    Возможно, хорошим вариантом будет Rust . Это молодой язык, и не факт, что он пригодится вам в ближайшие пару лет, но для обучения у него есть несколько преимуществ:
    • С одной стороны, он предсказуем, как и C++, т.е. обычно достаточно очевидно, как будет выполняться тот или иной кусок кода на низком уровне. С другой, он достаточно прост (ненамного сложнее JAVA) и автоматизирует управление ресурсами (без сборщика мусора, но так даже лучше).
    • Как и в C++, можно использовать абстракции с нулевой стоимостью (чего в Java нет в принципе), и для этого не требуется сложный шаблонный код.
    • Компилятор обругает вас за допущенные ошибки. Если не обругает компилятор - в большинстве случаев будет ошибка времени выполнения. C++ тоже часто находит ошибки во время компиляции, но в Rust это реализовано лучше, при этом на C++ сложнее искать ошибки времени выполнения. В JAVA ошибки по большей части возникают во время выполнения, что не очень хорошо для обучения - многие ошибки на простых примерах просто не возникают.
    • Модель управления ресурсами изначально учитывает многопоточность, что снижает вероятность возникновения ошибок в многопоточных программах.
    • Есть стандартный менеджер пакетов и система сборки, чего сильно не хватает C++. У Java тоже есть неплохие менеджеры пакетов, но их несколько, пусть и совместимых, что иногда осложняет жизнь.
    • У него неплохой стандартный учебник, в том числе на русском, в который я в любом случае рекомендую заглянуть: rurust.github.io/rust_book_ru/README.html . Правда, у С++ и Java тоже с этим особых проблем нет, разве что сложнее выбрать подходящий.


    Если вы всё же выбираете между C++ и Java - выбор в основном должен зависеть от того, сколько времени вы готовы потратить на изучение. Для изучения C++ нужно несколько лет (существует мнение, что около 5 лет), при этом нет смысла изучать C++ на базовом уровне - его достоинства проявляются только при хорошем знании языка. Java проще для изучения, довольно быстро можно достичь уровня, необходимого для устройства на работу, многие перспективные инструменты изначально разрабатываются на/для Java (например, экосистема BigData сейчас вертится вокруг Java и Scala, многие СУБД тоже ориентированы на Java). Но в случае выбора другого языка для изучения Java потом при необходимости можно будет быстро освоить, да и популярные инструменты обычно предоставляют интерфейсы для других языков, так что ориентироваться на конкретные инструменты не стоит.

    P.S. Я сам программирую на C++, Java (а чаще - Scala) использую только для научной работы (BigData и т.п.), и в целом C++ мне нравится больше. Но в будущем планирую перейти на Rust в качестве основного языка.
    Ответ написан
  • Как передать лямбду-функцию по ссылке, а затем присвоить в переменную?

    @Ariox41
    Для начала, сохранять функцию обратного вызова в глобальной переменной - уже плохая идея. Иногда имеет смысл сохранять call back в неизменной статической переменной, например, для ручной реализации таблицы виртуальных функций:
    static constexpr std::array<callbackType, n>
    Но к этому нужно подходить с осторожностью. Возможно, в глобальную (лучше - в статическую) переменную нужно сохранять не функцию, а как раз переменные, которые нужно захватить.

    Но если всё же хотите, должен сработать такой вариант:
    template<class Rt, class Fn>
    Rt static_capture(Fn fn){
      static Fn state = std::move(fn);
      return []{ 
         state();
      };
    }
    
    int main() {
      int localVar = 5;
      setit(static_capture<callbackType>([localVar](int num) {
        std::cout << num;
        std::cout << localVar;
      }));
    }


    Тут для каждой лямбды будет своя конкретизация шаблона и, соответственно, своя статическая переменная.

    Что касается std::function - в худшем случае она работает в два раза медленнее, чем обычные виртуальные функции. Можно написать свою реализацию специально для лямбд, которая будет работать чуть быстрее за счет меньшей универсальности, но принципиально ситуацию это не меняет - в большинстве случаев это незначительные расходы. Если всё же нужно оптимизировать - нужно менять архитектуру программы, передавать лямбды в качестве шаблонных параметров непосредственно к месту вызова, если это возможно (тогда они инлайнятся), использовать те же виртуальные функции и классические механизмы ООП.
    Ответ написан
    Комментировать
  • Какую вы знаете литературу о внутренностях С++?

    @Ariox41
    Многое из того, что вы хотите есть у Майерса. Он дает советы по использованию различных возможностей C++, в процессе разъясняя, почему нужно делать именно так (т.е. как оно работает), в каких случаях это не работает и почему у некоторых конструкций такой неудобный синтаксис. По C++03 - это "Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ", там есть немного устаревшие вещи, но для понимания причин добавления различных элементов в новые стандарты это даже полезно. Её дополняет "Эффективный и современный С++. 42 рекомендации по использованию C++11 и C++14" - там про новые стандарты, с предыдущей практически не пересекается.

    Много интересных статей на английском (точнее, ссылок на них) есть на https://www.reddit.com/r/cpp/ , но это больше для просмотра актуальных новостей, целенаправленно искать там что-то довольно сложно.
    Ответ написан
    Комментировать
  • Как подключить cxxtest к проекту с использованием IDE Clion?

    @Ariox41
    Не особо знаком с Clion и сххtest, но в CMake есть CTest, который позволяет добавлять произвольный исполняемый файл как тест (т.е. в CMakeLists указывается, что результат компиляции таких-то cpp файлов является тестом), и позволяет указывать аргументы командной строки при запуске теста. После конфигурации тесты запускаются командой make test или аналогичной для других систем сборки, что скорее всего можно прописать уже в настройках Clion: либо в настройках запуска проекта, либо как внешний инструмент.
    Ответ написан
    Комментировать
  • Как правильно написать тесты?

    @Ariox41
    Тестируется только интерфейс. Реализация для того и инкапсулирована, чтобы иметь возможность менять её произвольно, без зависимостей. Если реализация достаточно сложна для возникновения потребности в её тестировании - вам нужно вынести её в отдельные функции / классы, и тестировать уже их публичные интерфейсы как независимые модули.
    Ответ написан
    Комментировать
  • Что есть в C++, чего нет в C#?

    @Ariox41
    Принципиальное отличие C++ в том, что это язык с zero cost abstractions. Т.е. на нём можно реализовывать высокоуровневые абстракции, которые во время компиляции развернуться в код, эквивалентный коду на чистом c, написанному для решения той же задачи. Конечно, на практике всё не так гладко, многих функций C++ всё еще не хватает, но большинство других языков такой возможностью не обладают в принципе. Пока что для C++ реальным конкурентом в этом плане является разве что Rust, да и то скорее в будущем, чем в настоящем.
    Ответ написан
    Комментировать
  • Что читать после "Программирование: принципы и практика с использованием C++" Страуструпа?

    @Ariox41
    Майерса обязательно стоит почитать, хотя бы по диагонали. Начать лучше с "Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ" - там в основном про C++03, но большая часть всё еще актуальна. Затем можно переходить к "Эффективный и современный С++. 42 рекомендации по использованию C++11 и C++14".

    По многопоточному программированию на C++11 стоит почитать "Параллельное программирование на С++ в действии. Практика разработки многопоточных программ" Энтони Уильямса. По этой теме я ничего лучше пока не видел.

    Тут правильно говорят, что помимо чтения нужно еще и практикой заниматься, но придумать себе задачу обычно не просто. Я бы рекомендовал для начала изучать boost и пытаться запустить и модифицировать примеры из документации. Еще лучше - реализовывать эти примеры без копирования из документации. Это, конечно, не идеально, но лучше, чем ничего.
    Ответ написан
    Комментировать
  • Как передать counter is for loop внутрь макроса?

    @Ariox41
    Обычно используется примерно такое решение:
    #include <iostream>
    
    #define CHECK_EQ(a, b) \
      do{ \
      if ((a) != (b)){    \
        std::cout << "Values are not equal: \"" << a << "\" != \"" << b << "\"" << std::endl \
        << "\tleft expression: \"" << #a << "\"\n\tright expression: \"" << #b << "\""  << std::endl  \
        << "\tin \"" << __FILE__ << ":" << __LINE__ << "\"" <<std::endl; \
      } \
      }while(0)
     // while(0) для того, чтобы поставить ; после макроса.
     
    int main()
    {
      int a = 1;
      for(int i = 0; i < 3; ++i){
          CHECK_EQ(a + 1, i);
      }
    }


    Вывод:
    Values are not equal: "2" != "0"
    	left expression: "a + 1"
    	right expression: "i"
    	in "<...>:17"
    Values are not equal: "2" != "1"
    	left expression: "a + 1"
    	right expression: "i"
    	in "<...>:17"
    Ответ написан
    Комментировать
  • Актуально ли сейчас метапрограммирование на С++?

    @Ariox41
    Если вы про метопрограммирование шаблонов, то да - актуально. Более того, комитет по стандартизации прикладывает некоторые усилия для того, чтобы метопрограммирование в c++ стало проще для понимания и использования, т.к. это в конечном итоге позволяет повысить качество кода. В стандартной библиотеке сейчас на самом деле довольно часто прямо или косвенно используется метопрограммирование, например, при формировании условий для SFINAE, или для таких вещей, как `std::bind` и `std::variant`. Конечно, на практике обычно достаточно того, что уже есть в библиотеках, но не всегда.

    Тут на самом деле есть большая проблема: если вы изучите метопрограммирование, то на практике его применить будет сложно из-за того, что ваши коллеги с ним не знакомы. Т.е. если вы создадите какой-то модуль с использованием метопрограммированиея, при его использовании может получаться более читаемый и качественный код. Но код самого этого модуля будет не читаем для большинства ваших коллег.

    Если вы всё же хотите изучать метопрограммирование, для начала рекомендую ознакомится с этой статьёй: Simple C++11 metaprogramming, а далее изучать boost::hana (т.к. там довольно хорошая документация).
    Ответ написан
    Комментировать