• Как понять rvalue ссылки? Когда использовать std::move, а когда std::forward?

    @Mercury13
    Программист на «си с крестами» и не только
    Я их называю «врéменные ссылки» — то есть ссылки на временный безымянный объект, возникший в процессе вычисления значения выражения. Отличается тем, что обычно ссылки на временные объекты принимают заоптимизированные деструктивные функции, которые этот объект готовы выпотрошить в своих целях.

    Функция move предназначена для превращения ссылки (именованной или временной) во временную. Например, чтобы сказать: это именованный объект, но спокойно потрошите его, мне он не нужен.

    У Си++ есть одна фишка:
    void bar(std::string&& x) {}
    
    void foo(std::string&& x) {
      bar(std::move(x));
    }
    
    int main() {
      std::string x = "Test";
      foo (std::move(x));
      return 0;
    }

    То есть снаружи foo требует временную ссылку. Но внутри эта ссылка для ошибкобезопасности обычная именованная! В данном случае, когда функция нешаблонная, мы можем поставить move, но что делать в шаблоне?

    Автоопределение типов тут пасует, потому приходится так.
    template <class T>
    void foo(T&& x) {
      bar(std::forward<T>(x));
    }

    Да, я написал «ошибкобезопасность», хотя функция типа усложняет код. Дело в том, что потеря данных всегда хуже, чем неоптимальный код.

    Таким образом, move — это превращение ссылки (обычной или временной) во временную. Что-то вроде: «Потрошите этот объект спокойно, он мне не нужен».

    Forward — это прикидка, по какой ссылке (обычной или временной) мы передавали объект в функцию, и передача по цепочке таким же образом. Используется только в шаблонах.

    Вот моё описание всего этого.
    https://mercury13-kiev.livejournal.com/96961.html
    Ответ написан
    Комментировать
  • Что посоветуете изучать дальше?

    Steel_Balls
    @Steel_Balls
    0L3QsNGH0LjQvdCw0Lsg0YEgQkFTSUMg0L3QsCDQo9Ca0J3Qpi
    А теперь остановись и ничего не читай.
    Пришло время практиковаться. Устраивайся в команду работать.
    Через два-три года практики снова возвращайся к книгам, чтобы понять что ты писал говнокод и как ты мог его изменить. И начинай всё переписывать или уходи в другую команду с новым опытом
    Ответ написан
    8 комментариев
  • С чего начать практику администрирования без скучных книг?

    CityCat4
    @CityCat4
    //COPY01 EXEC PGM=IEBGENER
    Хотелось бы получить советы от человека который работает в данное время админом и знает о чем говорит.

    Ну вот тебе совет от человека, который с UNIX-системами работает с 1995 года :) (SCO UNIX, BSD OS, FreeBSD 2.2.5...). Сейчас я правда формально не админ, а кибербезопасник, но линухами стал заниматься ... больше :)

    Работа админом предполагает постоянное - понимаешь, постоянное! - обучение, в том числе и чтение скучной документации. И написание еще более скучной. Админство - это не тикток, тут не бывает модно-стильно-молодежно (хотя некоторые тенденции такими называются :) ) Если я, скажем, за день ничего нового не узнал - хотя бы с воробьиный хвост - день прошел зря.

    Какую бы задачку решить? Ну вот вариант задачки от Drno - возьми VPS, настрой к нему туннель и сделай возможность заходить на сайты, которые блокируют доступ по российским IP, причем на те, у которых "расширенная" проверка - ibm.com, latticesemi.com (это неполный список, но если что я накидаю - у меня на работе он есть). Это в основном производители электронных компонентов.
    Ответ написан
  • Что посоветуете изучать дальше?

    @Wan-Derer
    Зобанели на Хабре, волки́ ;((
    Зависит от того в какой области ты планируешь практиковаться. Если "под винду", то да Win API. Если бизнес-задачи, то скорее всего это будет Web, а значит C# (или Java, или Python) + Web-фреймворки. Если наука, анализ данных, то Python + соответствующие фреймворки.
    И обязательно SQL - он нужен везде и всегда.
    Ответ написан
    4 комментария
  • Что посоветуете изучать дальше?

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

    "Разработчик ПО" - таким термином можно буквально любую вакансию разработчика описать (исключение - железячники)

    Какой у тебя выбор:
    1. Посмотреть, где востребован язык Си и C++, выбрать то что тебе интересно, продолжать учёбу в этом направлении.

    2. Раз уже упомянуто winapi - значит ты хочешь разрабатывать десктопные приложения под Windows. Тут действительно очень популярен C#, хотя саму сферу я бы очень уж большой не назвал. Тогда изучай C# и какой-нибудь WPF.
    winapi и WinUI, в принципе, можно изучать и с C++.

    3. Раз уже прозвучал C#, то тут могу посоветовать более популярное направление в нём - разработка бэкенда (серверного ПО) на asp net core.
    Ответ написан
    2 комментария
  • Как создать шаблон структуры, которая будет принимать базовые типы данных и класс vector?

    @dima20155
    you don't choose c++. It chooses you
    Можно использовать перегрузку оператора <<
    Можно использовать новомодный std::input_or_output_iterator или if constexpr
    или вовсе явно специализировать/перегрузить шаблон для нужного вам типа.

    Вот один из простейших вариантов. Просто добавьте перед функцией main.
    template <typename T>
    std::ostream& operator<<(std::ostream &os, const S<T>& s)
    {
        if constexpr (std::ranges::range<T>) {
            const auto& val = s.GetVal();
            for (const auto& i : s.GetVal()) {
                os << i << " ";
            }
        } else {
            os << s.GetVal();
        }
        return os;
    }


    Все ещё не универсально, поскольку работает не со всеми контейнерами, а только с теми, которые хранят значения и могут в range_base loop

    В таком случае вам больше не нужны функции (если они использовались лишь для вывода информации в консоль)

    PrintVal
    PrintVector
    GetVector

    Можно даже избавиться от GetVal, если вам не нужен этот геттер в остальном коде, тогда нужно просто подружить функцию с классом.
    Ответ написан
    4 комментария
  • В чём отличия языка Си и С++? Зачем нужен Си?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    По учебнику, фундаментальных отличий три: классы, шаблоны и исключения. По факту там еще целый ворох мелких различий и это два вообще разных языка, хоть и слегка похожих.

    C сейчас используется в основном там, где легаси (куча старого кода в проекте уже на C), или где очень жесткие требования к легкости окружения исполнения языка (микроконтроллеры всякие).
    Ответ написан
    2 комментария
  • Почему запускается деструктор в данном примере?

    @vanyamba-electronics
    Просто у вас ошибка в этой строке
    MyString MyString::Copy(const char *string) { }
    Вы возвращаете копию объекта. Он нигде не используется:
    MyString::MyString(const char *string)
    {
      Copy(string); // Вот здесь
    }

    И для этой копии вызывается деструктор.

    А должно быть так:
    MyString& MyString::Copy(const char *string) { }
    В этом случае метод вернёт ссылку на объект.

    Но тогда вам следует объявить этот метод как статичный и назвать его не "копировать", а "создать":
    class MyString {
       MyString(const char* string);
       static MyString* Create(const char *string);
    };
    
    MyString::MyString(const char *string)
    {
      m_length = StrLen(string);
      m_string = new char[m_length + 1];
    
      if (m_string != nullptr) {
         for (size_t i = 0; i < m_length; ++i)
           m_string[i] = string[i];
    
           m_string[m_length] = '\0';
       }
    }
       
    MyString* MyString::Create(const char *string)
    {
      return new MyString(string);
    }

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

    В C++ нет стандартного соглашения, как должен поступить компилятор с объектом, возвращённым из функции по ссылке. Одни компиляторы такие объекты просто тихо удаляют, другие - нет.
    И вот, у вас объект в памяти есть, вы его не удаляли, и он даже доступен. Всё работает.
    Но потом вы создаёте какой-то новый объект, и у вас крашится программе при попытке доступа к прошлому объекту.
    Что такое? Почему компилятор сгенерил код, который затирает память? Куда подевался объект в том месте программы, в котором раньше всё работало?
    Просто физически нереально отыскать место возникновения ошибки через неделю, за которую вы написали ещё 30 тысяч строк кода.
    Поэтому всегда возвращайте объект из функции только по указателю.
    Ответ написан
    Комментировать
  • Почему запускается деструктор в данном примере?

    @rPman
    Сам copy никак не вызывает деструктор
    деструктор будет вызван автоматически по завершению области действия места где объект был создан, т.е. после завершения main

    Если же ты добавляешь *this в return Copy то у тебя возникает вызов деструктора этого возвращенного объекта, который не используется, а затем еще раз по завершению программы, собственно программа у тебя будет мусор на экран выводить вместо ожидаемого hi.

    Добавь в деструктор вывод на экран "destructor", увидишь

    Причина (если честно для меня не очевидная) в том что ты мешаешь два подхода - работа с объектами и работа со ссылкой на объект, преобразованный в сам объект (return *this), рекомендуется не мешать эти два подхода
    Ответ написан
    Комментировать
  • Как работать с указателями?

    CityCat4
    @CityCat4 Куратор тега C
    //COPY01 EXEC PGM=IEBGENER
    А, простите, чего хотели-то? Передали в функцию два указателя, поменяли первый со вторым, ничего с данными по указанным адресам не сделали - ничего и не поменялось :)

    Указатель содержит адрес. Чтобы поменять данные - нужно считать данные по адресу.
    Ответ написан
    Комментировать
  • Как работать с указателями?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы там поменяли местами значкения двух переменных указателей. Поскольку переменные (указатели) переданы по значению, то вне функции ничего не поменялось.

    Вы же менянте местами значения int, значит временная переменная tmp должна быть int, а указатели надо разименовывать.
    Ответ написан
    Комментировать