Pull to refresh
2
0

User

Send message

Мне в первые годы изучения помогло прочитать книгу "Дизайн и эволюция C++", чтобы понять, почему язык получился такой сложный. Это дало какое-то базовое чувство языка и прибавило уверенности при его использовании.

По шаблонам самая полная информация, на мой взгляд, содержится в томике "Шаблоны C++. Справочник разработчика".

Мне кажется объяснение с ассемблером получилось сложнее, чем могло бы быть с https://cppinsights.io

В C++ лямбда функция - просто синтаксический сахар для класса с перегруженным оператором вызова `ret operator()(args...)`.

Если у лямбды пустой список захвата, то в сгенерированный класс добавляется оператор приведения к указателю на функцию: https://cppinsights.io/s/dab279d2

Если список захвата не пустой, то в сгенерированный класс добавляются соответствующие поля (ссылки для & или значения для =) и приведение к указателю на функцию невозможно, так как для вызова требуется экземпляр лямбды: https://cppinsights.io/s/5e323673

Пару недель назад читал пост на эту тему в канале Experimental chill
https://t.me/experimentalchill/211

В описании std::vector небольшая неточность - стратегия роста емкости никак не указана в стандарте, так что это деталь реализации. В stdlibc++ и libc++ это удвоение размера, но вроде бы в Visual C++ используется множитель 1.5

Еще у Matthew Bentley, автора Colony, есть интересный документ про рост емкости для deque-like контейнера: https://plflib.org/matt_bentley_-_pot_blocks_bit_tricks.pdf

А как ваш парсер JSON относится к Infinity или NaN значениям? Они ведь тоже не часть спецификации.

Желание усидеть на двух стульях понятно, но с плавающей точкой это невозможно. Либо побитовово точное хранение (a hex float оно и есть), либо человекочитаемое с потерей точности.

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

Но если действительно требуется сохранять точность, то можно просто почитать документацию и отформатировать float с флагом "a" - "converts floating-point number to the hexadecimal exponent notation."

А почему не рассматривался 4-й вариант: написать Native Addon для Node.js использую https://nodejs.org/api/n-api.html#node-api ?

Даже если поблизости нет C или С++ программиста, то вроде бы в Go можно сделать библиотеку, экспортирующую функции в C стиле, и использовать их с Node-API

Да, действительно, только что clang-13 без проблем собрал ядро 5.15.6

Видимо clang стал еще более совместим с gcc и/или из ядра таки выпилили gcc-only код.

Мне вот интересно стало, если Линусу не нравится реализация GCC, то где можно увидеть ядро, собранное альтернативным компилятором? И легко ли это сделать в принципе?

Проект, на котором я сейчас работаю, успешно собирается на С++ компиляторах от 3-х вендоров. Этот проект бесконечно мал, по сравнению с ядром Линукса, но и ресурсы на его разработку также бесконечно малы.

Вопрос: если новый компилятор GCC так не устраивает Торвальдса, то почему он ест этот кактус?

И в чем смысл переводить статью годовалой давности? Так то C++20 уже принят и полным ходом разработка C++23

Со сменой типа параметров это может быть чуть проще. При желании можно добавить перегруженную версию ParseFromArray(const void* data, size_t size), опционально пометить ParseFromArray(const void* data, int size) как deprecated.

При смене возвращаемого типа тоже все решаемо, например какByteSize() -> ByteSizeLong().

Проблема в точке зрения авторов protobuf, что int для размеров это нормально.

Похоже здесь static_cast<size_t> был добавлен просто для того, чтобы задушить предупреждение компилятора о преобразовании знакового int в беззнаковый size_t.

Любовь Гугла к int для индексов и количества элементов в контейнере все время наталкивается на реальность стандартной библиотеки, где для этого используется size_t.

Но больше всего меня, как пользователя protobuf, раздражает их использование int для размера буфера. Ведь в Гугле уверены, что 640 кБ 2 ГБ хватит всем. Поэтому я останавливаюсь, вздыхаю и мысленно ругаюсь, когда приходится писать или читать кода вида

const std::string buf = protobufMessage.SerialzeAsString(); // ага, авторы protobuf решили, что std::string это самый подходящий тип для буфера с бинарными данными

protobufMessage.ParseFromArray(buf.data(), static_cast<int>(buf.size())); // избавляемся от предупреждения и верим что тут всегда будет меньше 2 ГБ

Это очевидно не так для node-based контейнеров типа std::map|set, где ссылка (и указатель тоже) на элемент в контейнере будет всегда действительна до удаления элемента.

Но недавно я узнал, что ссылка на элемент в std::unordered_map|set также действительна до удаления. Я был уверен, что они могут стать недействительными при вставке, если происходит rehashing. Однако, в документации говорится, что недействительными при вставке могут стать только итераторы:

If an insertion occurs and results in a rehashing of the container, all iterators are invalidated. Otherwise iterators are not affected. References are not invalidated.

https://en.cppreference.com/w/cpp/container/unordered_map/operator_at

Так что внимательное чтение документации иногда может быть полезно.

Нет, внутри push_back(T&&) аргумент имеет имя _Val и является lvalue, которое нужно двигать дальше в emplace_back(), безусловно превращая _Val в rvalue с помощью std::move().

В примере с make_unique(Types&& ... _Args) параметры `_Args` могут быть как lvalue, так и rvalue, значит применяем std::forward<Types>(_Args)..., которая на этапе компиляции разберется, где l- и где r-value.

Неформально я запомнил это для себя так: если шаблонный параметр надо передать куда-то дальше, то используем для передачи std::forward():

template<typename T> func(T&& arg)

{

// SomeClass has a constructor for T

std::vector<SomeClass> vector;

vector.emplace_back(std::forward<T>(arg));

}

Для не шаблонной rvalue ссылки используем, если надо, std::move():

void func(std::string&& str)

{

std::vector<std::string> vector;

vector.push_back(std::move(str));

}

Полезно для начала было бы изучить опыт предшественников. Подход 1 поток на каждого клиента был признан несостоятельным еще в прошлом веке, и сформулирован как C10K problem в 1999 году.


Примерно с 2005 в C++ доступна boost.asio позволяющая писать кросс-платформенные асинхронные многопоточных сетевые приложения, в том числе и http серверы.


После массового перехода на C++11 стали доступны такие библиотеки как boost.beast, restinio. Наверно после принятия сопрограмм в C++20 появятся или уже появились новые версии.


Ngnix, насколько я помню, написан на C, совсем другом языке. На C++ сделан Envoy, если хочется посмотреть на устройство proxy сервера.

В hren.hpp определено


class Hren
{
private:
    int a;
};

В hren.cpp лежит реализация, всё ок


#include "hren.hpp"
...

В hack_hren.cpp хотим по какой-то причине иметь доступ ко внутренносятм


#define private public
#include "hren.hpp"
...

Разные определения Hren в разных единицах трансляции -> ODR.


Еще в https://stackoverflow.com/a/27779038/1355844 утверждается, что само по себе переопределение ключевых слов — это UB, если в такой единице трансляции включается заголовочный файл стандартной библиотеки.


На практике такого пока не наблюдается, но не хотелось бы получить проблемы на ровном месте, даже в теории.

Вроде бы это нарушение one definition rule, с теоретически побочным эффектом undefined behaviour

Почему бы в 21-м году 21-го века не воспользоваться достижениями прогресса, и не переложить заботы по управлению памятью на С++. Тогда с помощью https://github.com/pybind/pybind11 пишем на C++ модуль


#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

struct Pet {
    Pet(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }

    std::string name;
};

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

    m.def("add", &add, "A function which adds two numbers");

    py::class_<Pet>(m, "Pet")
        .def(py::init<const std::string &>())
        .def("setName", &Pet::setName)
        .def("getName", &Pet::getName);
}

и используем его в Python:


>>> import example
>>> example.add(1, 2)
3L
>>> p = example.Pet('Molly')
>>> print(p)
<example.Pet object at 0x10cd98060>
>>> p.getName()
u'Molly'
>>> p.setName('Charly')
>>> p.getName()
u'Charly'

А можно посмотреть на сравнение с другими методами? Например, pull-request в https://github.com/miloyip/dtoa-benchmark было бы круто.

Information

Rating
Does not participate
Registered
Activity