• Для чего нужны замыкания в C++ и как вы их используете?

    @Mercury13
    Программист на «си с крестами» и не только
    Замыкание — это способ передать в callback, из какого контекста он запустился.
    struct Row {
      int data[10];
    };
    struct Table {
      Row rows[10];
    }

    Нам нужно отсортировать таблицу по j-му столбцу. Номер j заранее неизвестен.

    int sortJ;
    
    int myCompare(const void* a,const void* b) {
      int ia = reinterpret_cast<Row*>(a)->data[sortJ];
      int ib = reinterpret_cast<Row*>(b)->data[sortJ];
      if (ia < ib) return -1;
      if (ia == ib) return 0;
      return 1;
    }
    
    int someJ = 5;
    sortJ = someJ;
    qsort(table.rows, 10, sizeof(Row), myCompare);

    Вот эта переменная sortJ — по какому столбцу сортировать — это и есть замыкание. Но, как известно, «избегай незнакомых женщин и глобальных переменных». Поэтому на STL мы делаем функтор (объект-функцию) и эту информацию кидаем в него.

    class MyCompare {
    public:
      MyCompare(int aJ) : j(aJ) {}
      bool operator () (const Row& a, const Row& b) const
        { return (a.data[j] < b.data[j]); }
    private:
      const int j;
    }
    
    int someJ = 5;
    std::sort(table.rows, table.rows + 10, MyCompare(someJ));

    Вот мы и избавились от глобальной переменной, закинув наше замыкание в private-поля объекта.

    Что плохо? Не будем говорить про технические тонкости. С точки зрения красоты и лаконичности кода: код слишком разлапистый. И тут пришёл C++11.
    int someJ = 5;
    std::sort(table.rows, table.rows + 10,
      [someJ](const Row& a, const Row& b) -> bool { return (a.data[someJ] < b.data[someJ]); } );

    Корявовато, но таков синтаксис Си++. Автоматически создаётся объект-функтор, и someJ становится его полем. Вот оно, замыкание — [someJ] — то есть те вещи, которые надо протащить внутрь функтора.

    Из реального проекта. Отбегал поток автоматического поиска нового регистрационного ключа; если что-то получилось — синхронно вызываем лямбду через Qt’шный механизм «сигнал-слот». Чтобы всё было синхронно, нужен объект, живущий в главном потоке (и он в интерфейсе MainControl — управление главной формой — тоже есть). Но тогда придётся вызывать не слот, а лямбду. Этой лямбде нужны два поля: fReregKey (новый ключ защиты от копирования) и fMainControl. Оба они в this, его и замыкаем.
    connect(this, &RenewThread::needUpdate, fMainControl.maincQobj(),
                [this]() {
            drm::createFile(fReregKey);
            fMainControl.maincLayoutOnRegister();
        });


    А теперь посмотрим в WinApi. Первая попавшаяся функция из DirectInput.
    HRESULT EnumObjects(
             LPDIENUMDEVICEOBJECTSCALLBACK lpCallback,
             LPVOID pvRef,
             DWORD dwFlags
    );
    
    BOOL DIEnumDeviceObjectsCallback(
             LPCDIDEVICEOBJECTINSTANCE lpddoi,
             LPVOID pvRef
    );

    Про pvRef говорится: функции EnumObjects он ни на что не нужен; что функция приняла, то и даст в callback. Тоже форма замыкания: можно передать указатель на любые данные, которые нужны callback’у.
    Ответ написан
    4 комментария
  • Для чего нужны замыкания в C++ и как вы их используете?

    Замыкания неотделимы от лямбд. Они позволяют передавать в лямбду ссылки. Например в лямбде вам потребовалось менять приватную переменную класса. Без замыкания вам пришлось бы делать сеттер и геттер (что уже меняет интерфейс класса, их можно будет вызвать там, где не стоило бы), передавать в лямбду указатель на объект.
    А так вы работаете с переменной объекта внутри лямбды, как будто это локальная переменная лямбды.

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    using IntV = vector<int>;
    
    int main(int argc, char const *argv[]) {
    
      IntV v = {0, 9, 4, 6, 7, 8, 5, 6};
      size_t count = 0;
    
      for_each(begin(v), end(v), [](IntV::value_type x){cout << x << " ";});
      cout << endl;
    
      sort(begin(v), end(v), [&count /*closure*/](IntV::value_type &a, IntV::value_type &b){
        ++count;
        return a < b;
      });
    
      cout << count << endl;
    
      for_each(begin(v), end(v), [](IntV::value_type x){cout << x << " ";});
      cout << endl;
    
      return 0;
    }


    Вот пример вам подсчёта количества сравнений при сортировке вектора.
    Ответ написан
    3 комментария
  • Почему не работает код?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    На первом шаге цикла:
    k = 1
    f = f*k = 1*1 = 1
    z = z + 1 / (k + 1) = 0 + 1 / (1 + 1) = 0 + 1 / 2 = 0 + 0 = 0
    s = s + (f / z) = 0 + (1 / 0)

    На ноль делить запрещено!
    Ответ написан
    5 комментариев
  • Не удалось получить доступ к флешке, как считать данные?

    Если вы уверены, что это exfat, то
    sudo apt-get install exfat-fuse exfat-utils
    sudo mount -t exfat /dev/sdb1 /media/mefisto/Новый
    Ответ написан
    1 комментарий
  • Как запустив программу через командную строку получить её Exit Code?

    Casper-SC
    @Casper-SC Автор вопроса
    Программист (.NET)
    Для Linux:
    using System;
    using System.Diagnostics;
    using System.IO;
    
    namespace Test
    {
    	class MainClass
    	{
    		public static void Main (string[] args)
    		{          
    			string result = LinuxTerminal.GetOutput("find /sys/class/input -maxdepth 1  -name \"mouse*\"|wc -l");
    			int outputValue = int.Parse (result);
    			Console.WriteLine (outputValue);
    			Console.ReadKey ();
    		}
    	}
    }


    using System;
    using System.Diagnostics;
    
    namespace Test
    {
    	public static class LinuxTerminal
    	{
    		private const string TerminalPath = "/bin/bash";
    
    		public static void ExecuteCommand(string command)
    		{
    			var proc = new Process();
    			proc.StartInfo.FileName = TerminalPath;
    			proc.StartInfo.Arguments = "-c \" " + command + " \"";
    			proc.StartInfo.UseShellExecute = false;
    			proc.Start();
    		}
    
    		public static int GetExitCode(string command)
    		{
    			var proc = new Process();
    			proc.StartInfo.FileName = TerminalPath;
    			proc.StartInfo.Arguments = "-c \" " + command + " \"";
    			proc.StartInfo.UseShellExecute = false;
    			proc.StartInfo.RedirectStandardOutput = true;
    			proc.Start();
    			proc.WaitForExit();
    			return proc.ExitCode;
    		}
    
    		public static string GetOutput(string command)
    		{
    			var proc = new Process();
    			proc.StartInfo.FileName = TerminalPath;
    			proc.StartInfo.Arguments = "-c \" " + command + " \"";
    			proc.StartInfo.UseShellExecute = false;
    			proc.StartInfo.RedirectStandardOutput = true;
    			proc.Start();
    			proc.WaitForExit();
    			return proc.StandardOutput.ReadToEnd();
    		}
    	}
    }


    Из под винды так работает запуск программы и получение ExitCode
    using System.Diagnostics;
    
    namespace ProcessStart
    {
        public static class CommandLine
        {
            public static int ExecuteCommand(string applicationPath, string command = "")
            {
                var proc = new Process();
                proc.StartInfo.FileName = applicationPath;
                proc.StartInfo.Arguments = command;
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                proc.Start();
                proc.WaitForExit();
                return proc.ExitCode;
            }
        }
    }


    using System;
    using System.IO;
    
    namespace ProcessStart
    {
        class Program
        {
            private static Program _program;
    
            static void Main(string[] args)
            {
                _program = new Program();
                _program.Run();
            }
    
            private void Run()
            {
                const string ProgramName = "ReturnRandomNumber.exe";
                string appName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ProgramName);
    
                int exitCode = CommandLine.ExecuteCommand(appName); 
                Console.WriteLine(exitCode.ToString());
    
                Console.ReadKey();
            }
        }
    }
    Ответ написан
    Комментировать
  • В каких случаях использовать .h и .hpp?

    GavriKos
    @GavriKos
    Технически компилятору вообще все равно какое вы расширение поставите - вы все равно указываете при инклуде полное имя с полным расширением. Поэтому ставьте как принято в вашей нейминг конвенции.

    Про с++ и с - в принципе вы правы, однако это рекомендация, а не правило.
    Ответ написан
    Комментировать
  • Как разнести класс по файлам?

    @Mercury13
    Программист на «си с крестами» и не только
    Принцип прост. В .h можно ставить только то, что не производит кода. Как только в проекте появится второй CPP и задействует этот хедер, код будет произведён дважды, и компоновщик (cl/ld/ilink) будет ругаться, что переменная или функция в двух экземплярах. Что именно не производит кода…
    • Определения макросов. Они в принципе кода не производят.
    • Объявление любого типа. Оно лишь говорит об устройстве этого самого типа; код же производят те, кто этим типом пользуются.
    • Шаблоны. Код производит не сам шаблон, а факт расшаблонивания. Разумеется, шаблон может расшаблониться в двух единицах компиляции, но с этим автоматически бороться научились.
    • inline—  код производит не сам inline, а факт включения. inline бывает как явный ключевым словом, так и неявный — в теле класса.
    • Прототипы и extern — они говорят: код есть, но где-то не здесь.
    • Constexpr C++11. Они подставляют значение.
    • Некоторые const в зависимости от компилятора. Например, на Borland const double производит код, а const int — нет.

    Производят код и в хедерах запрещены.
    • Переменная без extern, даже const.
    • Функция, которая не inline.
    • Полностью специализированный шаблон, в котором не осталось шаблонных параметров (template<>).

    Не производят кода, но и лучше закинуть в CPP.
    • Некоторые скрытые (private) inline и шаблоны, если они не используются из хедера.
    Ответ написан
    3 комментария
  • Как совместить гармонично совместить теорию и практику на C#?

    У меня наоборот было.
    Начитался про C#, а вот практики мало, и валился на простых вещах.
    Сейчас уже и эти пробелы закрыл.

    Раз книги читал, то сходи на ITVDN курс мидл и проф.
    Просто заучи, повторяй раз в неделю, месяц, полгода заметки из книг.
    Выписывай то что считаешь главным, своими словами.
    У меня набралось на 3-4 часа чтения.
    Но зато это покрывает ~5 книг сразу.

    Коллекция нужна только если используется Add, Remove. Книги то читали, вот например заметки из Jon Skeet C#:
    List - внутренне хранит массив и отслеживает логический размер списка и размер поддерживающего массива. Добавление элемента является либо простым случаем установки очередного значения в массиве, либо (если массив уже заполнен) копированием существующего содержимого в новый массив большего размера (обычно в два раза, т.е. происходит удвоение, но это недокументированно) и затем установки в нем значения. Сложность O(1) или O(n) в зависимости от того требуется ли копирование значений. Удаление элемента из List требует копирования расположенных за ним элементов на позицию назад, поэтому сложность составляет O(n-k), где k - индекс удаляемого элемента. По индексу RemoveAt() удалять значительно быстрее чем по значению Remove(), т.к. во втором случае происходит сравнение каждого элемента где бы он не находился сложность O(n).

    **Массивы** - самый низкий уровень коллекций в .Net. Унаследованы от System.Array, и они единственные имеют прямую поддержку в среде CLR. Массивы всегда изменяемы в терминах своих элементов, но всегда фиксированы в терминах своих размеров.
    Foreach для массива использует его свойство Length и индексатор массива, а не создает объект итератора.

    **LinkedList** - связанный список, каждый элемент которого имеет ссылку на предыдущий и следующий элемент. Быстро можно удалять, вставлять новые элементы, т.к. происходит только изменение ссылок на соседних узлах. Проход по коллекции тоже эффективен, но разумеется нет индекса.

    **Dictionary** - подобно List хранит свои элементы в массиве, со всеми вытекающими по вставке и увеличению размера последствиями. Для реализации эффективного поиска использует хештаблицу. Можно либо применять стандартные функции хеширования и эквивалентности внутри самих объектов ключей, либо передать реализацию IEqualityComparer в аргументе конструктора. Ключи должны быть уникальными, но хешкоды могут совпадать, что снижает эффективность поиска. Словарь даст отказ, если ключи являются изменяемыми и меняют свои хешкоды после того, как были вставлены в словарь. Внутри этого словаря нет гарантии порядка следования элементов, так что рассчитывать на него нельзя. Вставка происходит на основе ключа (что-то вроде индекса), а не последовательности заполнения словаря.

    **ReadOnlyDictionary<,>** - просто оболочка, которая скрывает все изменяемые операции за явной реализацией интерфейса, и генерирует исключение если они все же вызываются. Но если лежащая в основе коллекция (та что передается конструктору) модифицируется, то модификации будут видны через оболочку.


    APS.NET без рефлексии и доменов не работал бы.
    Ответ написан
    3 комментария
  • Что такое VirtualProtect?

    @none7
    ОС может блокировать для приложения возможность чтения, записи, исполнения определённых диапазонов виртуальной памяти. Например код *((char*)GetProcAddress(hkernel32, "GetProcAddress")) = 0 по умолчанию вызовет исключение. Но если выдать региону памяти права на запись, то первый байт функции в данном процессе будет успешно перезаписан.
    Ответ написан
    Комментировать
  • Можно ли реализовать следущий подход с помощью Generic типов?

    Nipheris
    @Nipheris Куратор тега C#
    interface IFoo
    {
      // Не содержит метод Commit()
      // Но содержит все остальные методы и свойства, которые реализованы в классе Foo
    }
    interface ITransaction
    {
        void Commit();
    }
    class Foo : IFoo, ITransaction
    {
      // ...
      
      public void Commit() 
      {
        // ...
      }
    }

    class Bar<T, TImpl> where TImpl : T, ITransaction, new()
    {
      private readonly TImpl _foo;
    
      protected T Foo {
        get { return _foo; }
      }
    
      public Bar() {
        _foo = new TImpl();
      }
     
      public void Commit()
      {
        _foo.Commit();
      }
    }
    Ответ написан
    3 комментария
  • Мало весящий IDE для С++?

    Daniro_San
    @Daniro_San
    Программист
    Из всех IDE для C++, самая лучшая что я знаю - это CodeLite.
    Среда быстрая, легковесная, постоянно обновляется.
    Code::Blocks в принципе обладает аналогичными свойствами но его портят глюки, ужасные шрифты и интерфейс "а ля Windows 95"
    Ответ написан
    Комментировать
  • Какая программа лучше для записи макросов?

    TomasHuk
    @TomasHuk
    1. На AutoHotkey, используя Pulover's Macro Creator.
    2. На AutoIt, используя AutoItMacroGenerator .
    Ответ написан
    Комментировать
  • Как автоматизировать повторяющиеся действия в windows?

    xmoonlight
    @xmoonlight
    https://sitecoder.blogspot.com
    Это делается через систему оконных сообщений windows на любом языке программирования.
    Лучший готовый софт - AutoiIt
    autoit_10_240x100.jpg

    Easy to learn BASIC-like syntax
    Simulate keystrokes and mouse movements
    Manipulate windows and processes
    Interact with all standard windows controls
    Scripts can be compiled into standalone executables
    Create Graphical User Interfaces (GUIs)
    COM support
    Regular expressions
    Directly call external DLL and Windows API functions
    Scriptable RunAs functions
    Detailed helpfile and large community-based support forums
    Compatible with Windows XP SP3 / 2003 SP2 / Vista / 2008 / Windows 7 / 2008 R2 / Windows 8 / 2012 R2
    Unicode and x64 support
    Digitally signed for peace of mind
    Works with Windows User Account Control (UAC)
    Ответ написан
    2 комментария
  • Как автоматизировать повторяющиеся действия в windows?

    savostin
    @savostin
    Еще один программист
    Ответ написан
    Комментировать
  • Мало весящий IDE для С++?

    Adamos
    @Adamos
    Полноценный (с анализом кода и прочими плюшками) и при этом легкий - вещи сугубо взаимоисключающие.
    VisualStudio с С++ ведет себя так, как будто рекламирует С# (ирония, но недалекая от истины). Анализ кода там тормозит безбожно, на слабом железе его просто не дождешься. Хотя, может быть, хэлловорды он и быстро будет прожевывать...

    Eclipse, NetBeans, Clion - это все-таки Java со всеми из нее вытекающими - медленно и печально. Для слабого железа опять-таки противопоказано.

    QtCreator - имеет довольно много плюсов, но объем действительно может зашкаливать, так как он тащит за собой весь Qt в обязательном порядке.

    Есть легкие Code::Blocks и CodeLite - в принципе, настолько легкие, что их просто стоит попробовать, а если будет некомфортно - тогда уже подниматься по этому списку вверх ;)

    Альтернатива в порядке бреда: поставить какую-нибудь древнюю VS, которая еще нормально жевала С++ на слабых машинках (то есть до 2008 версии). Если она запустится на "десятке", то для изучения "крестов" может вполне сгодиться. С++0х и С++11, правда, придется исключить из учебной программы.
    Ответ написан
    2 комментария
  • Мало весящий IDE для С++?

    AtomKrieg
    @AtomKrieg
    Давай я поищу в Google за тебя
    Code::block
    150метров
    Ответ написан
    Комментировать
  • Стал ли теперь C# бесполезным в интерпрайзе?

    yarosroman
    @yarosroman Куратор тега C#
    C# the best
    ASP.Net Core кроссплатформенный, без всяких бубнов на Linux работает. И верно сказали, не путайте бюджетников и корпорации.
    Ответ написан
    Комментировать