🍌 C++ Feed
305 subscribers
218 photos
12.7K links
Агрегатор всего подряд про C++.

Для связи: @smertig

Powered by https://github.com/Smertig/banana
Download Telegram
Arthur O’Dwyer
Inheritance is for sharing an interface (and so is overloading)

This blog post was inspired by my answer to a question
on Code Review StackExchange. To utterly oversimplify the question: When is it appropriate
to use classical inheritance?

struct Cat {
void meow();
};
struct Dog {
void bark();
};

// Should I write a struct AbstractAnimal?


Here’s what the same code would look like, with an AbstractAnimal base class
(and omitting the NVI
for pedagogical reasons):

struct AbstractAnimal {
virtual void do_speak() = 0;
};

struct Cat : public AbstractAnimal {
void meow();
private:
void do_speak() override { meow(); }
};

struct Dog : public AbstractAnimal {
void bark();
private:
void do_speak() override { bark(); }
};


The only reason to use a base class here is in order to write polymorphic code that operates
on (a pointer or reference to) that base class.

// If all my code looks like this, I don't need a base class.
void operateOnCat(Cat *c) { c->meow(); }
operateOnCat(myCat);

// I need the base class only if I want to write code like this.
void operateOnAnything(AbstractAnimal *a) { a->do_speak(); }
operateOnAnything(myCat);
operateOnAnything(myDog);




If you don’t need to write operateOnAnything, then you shouldn’t write AbstractAnimal.
Abstraction is a tool for solving problems — and, as such, it is also a signal to the reader
that a problem is being solved! If your code doesn’t actually need polymorphism in order
to work, then you should avoid making an inheritance hierarchy.


Keep it simple, stupid.


The design principles of polymorphic programming apply equally to generic programming…

When should I name two methods the same?

Notice that in our original Cat/Dog code, I named the two methods Cat::meow()
and Dog::bark(). It’s very tempting to give them the same name:

struct Cat {
void talk(); // meows
};
struct Dog {
void talk(); // barks
};


However, this is once again a signal to the reader that something indispensable is
going on here! Meowing and barking are vaguely similar at an abstract level, yes;
but abstraction is a tool for solving problems, and so we should avoid it unless
a problem exists to be solved.

The only reason to use the same name for meowing and barking, here, is in order
to write generic code that operates on an object of unknown type T.

// If all my code looks like this, I don't need to reuse the
// same name in both classes.
void operateOnCat(Cat& c) { c.meow(); }
operateOnCat(myCat);

// I need the same name only if I want to write code like this.
template
void operateOnAnything(T& t) { t.talk(); }
operateOnAnything(myCat);
operateOnAnything(myDog);


Notice that another way to ask “When should I name two methods the same?”
is to ask “When should I define a C++20 concept modeled by both these classes?”
The rules of classical OOP are isomorphic to the rules of generic programming with
concepts: just replace “base class” with “concept” and “derives from” with “models.”

Let’s go deeper.

When should I put two functions into an overload set?

The previous section was about reusing the same name outside of an overload set:
Cat::talk and Dog::talk aren’t “overloads” per se. But what about something like
this?

struct Snake {
void eatPellet(const Pellet&);
void eatCat(const Cat&);
};


Should we rename both methods to just Snake::eat, creating an overload set?

The only reason to use the sa
C++
periodic_function v0.1.0 released! Thank you all for the helpful feedback!

A while back I made my initial post about the periodic_function library I had created and I receive a ton of feedback. Thank you so much to everyone who commented. Your suggestions and critical eyes have made the library more robust and better overall. The suggestions and comments have been addressed in the v0.1.0 release and I hope some of you can find it useful. Thank you again! I really appreciate those who took the time to nitpick my code; it was eye-opening and a great learning experience. Release is here. submitted by /u/mrkent27
[link] [comments]
C++
Introducing fp library

Hi, the author of Dragonbox again. I'm now working on a more comprehensive library with features related to conversions between strings and floating-point numbers. It's in an early stage and is not really usable right now AFAICT, but I want to gather some opinions from you guys. Please take a look at the repo if you are interested. Any idea/feedback is very welcome, and contribution is even more welcome. As stated in the README, the goal of the library is to provide conversion algorithms between decimal and binary floating-point numbers rather than string parsing/formatting. String parsing/formatting routines provided in the library should be considered as proof-of-concepts, although I'll continue to work on improving them as well. Therefore, I put much effort on cleanly separate decimal/binary conversion routines from string parsing/formatting as much as possible. Currently, the library has the following features (with rudimentary/subject-to-change API's): Dragonbox: shortest-roundtrip binary-to-decimal conversion algorithm for formatting. The version in this library is not really different from the original implementation, except that it uses a larger table (in order to share it with the parsing algorithm). Ryu-printf: fixed-precision binary-to-decimal conversion algorithm for formatting. This is nothing more than just an implementation of the algorithm as written in the paper with a few modifications, but somewhat mysteriously it uses way fewer amount of static data compared to the original implementation by Ulf Adams. (I honestly have no idea why this happened.) But the size of static data is still huge; it's about 40KB. Dooly: limited-precision (9 for float's, 17 for double's) decimal-to-binary conversion algorithm for parsing. This is the one that I mentioned in the previous post about Dragonbox. Ryu library also provides a similar algorithm, and it seems that the performances of these algorithms are similar. Combining Dooly and (a slight extension of) Ryu-printf, string-to-float parsing for arbitrary length input is also possible. A gist of the idea is explained in the comment of /u/STL in this post. (I originally got the idea from discussions with fast_io's author, though.) /u/STL said that it might be agonizingly slow, but it turned out to be a lot faster than the current implementation of MS STL's std::from_chars. (To be fair, my implementation does way fewer error handlings so the actual performance gap should be somewhat smaller.) submitted by /u/jk-jeon
[link] [comments]
CppCon (Youtube)
Empirically Measuring, & Reducing, C++’s Accidental Complexity - Herb Sutter - CppCon 2020

https://cppcon.org/
https://github.com/CppCon/CppCon2020
---
We often hear “C++ is more complex than it needs to be,” typically demonstrated using anecdotes and “gotcha” examples. Those can be valid and demonstrate real pain points, but it would be nice to have more quantifiable data that we could analyze to measure sources of complexity. This talk reports work to systematically catalog and measure C++’s unneeded complexity, how some current evolution proposals may address its major sources, and presents specific suggestions on what we might be able to do about it in the context of a future-evolution proposal to simplify parameter passing and provide meaningful initialization guarantees in C++.

---
Herb is the chair of the ISO C++ standards committee, a programming...

Read full post
C++
Potential way to solve dangling reference to temporary?

When I am writing when() in SugarPP, I kept wondering how to deal with returning reference of possibly lvalue references and rvalue reference. To make it simpler, it's the same as cpp int x{}; auto&& bigger = std::max(x, -1); //... Use bigger, OK, but dangling if -1 is bigger I gave up by just return by value. But it's obviously not optimal if I also want to be able to modify through the reference (both the lvalue or the temporary), as if the temporary is also lvalue. Of course I can just give it a name to trivially solve it but still it's amazingly unintuitive. What if the compiler can implicitly generate a name to make the temporary to a lvalue when the function accepts reference (because temporary will still "materialize" anyway) at the current calling scope, but still interpret it as rvalues like this: cpp int x{}; int __temp = -1; auto&& bigger = std::max(x, std::move(__temp)); //... Use bigger, OK now submitted by /u/HO-COOH
[link] [comments]
C++ – Типизированный язык программирования
Тестирование приложений в условиях нехватки памяти

Вопрос о том надо ли проверять то, что возвращает malloc является спорным и всегда порождает жаркие дискуссии.

Часть людей считает, что надо пытаться обрабатывать все виды runtime ошибок, в т.ч. и OOM ситуации. Другие считают, что с OOM всё равно мало что можно сделать и лучше дать приложению просто упасть. На стороне второй группы людей ещё и тот факт, что дополнительная логика обработки OOM с трудом поддаётся тестированию. А если код не тестируется, то почти наверняка он не работает.

Я полностью согласен с тем, что не стоит реализовывать логику обработки ошибок которую вы не собираетесь тестировать. Почти наверняка она ничего не улучшит, а может и того хуже — всё испортит.

Вопрос о том надо ли пытаться обрабатывать OOM ситуации в библиотеках/приложениях является противоречивым и мы не будем его здесь касаться. В рамках данной публикации я лишь хочу поделиться опытом того как можно тестировать реализованную логику обработки OOM ситуаций в приложениях написанных на C/C++. Разговор будет идти об операционных системах Linux и macOS. Ввиду ряда причин, Windows будет обойдён стороной. Читать дальше →
C++ – Типизированный язык программирования
Релиз акторного фреймворка rotor v0.09 (c++)

rotorненавязчивый С++ акторный микрофремворк, похожий на своих старших братьев — caf и sobjectizer. В новом релизе внутреннее ядро полностью было переделано с помощью механизмов плагинов, так что это затронуло жизненный цикл акторов. Читать дальше →
C++
Want To Chat C++? Join The Best Technical C++ Chat Community!

If you would like to chat with other C++ engineers, get help on C++ topics, or participate and learn about the latest developments in the C++ Standard, there's a great place for you! It is called the Cpplang Slack and you can get a free invite here: https://cppalliance.org/slack Be sure to check out our #learn channel for answers to common C++ questions! This is the place to go if you want robust, technical C++ discussion without the politics! Please abide by our Acceptable Use Policy: https://cppalliance.org/slack/ submitted by /u/VinnieFalco
[link] [comments]
C++
Tips for debugging C++ code?

It's been years since I had a C++ job. I got back into it recently and finally hit a wall on debugging a problem. What are your techniques on debugging C++ problems? submitted by /u/Quiet-Smoke-8844
[link] [comments]
C++
Bjarne Stroustrup on "dead bodies of type theorists"

I can't produce a link off the top of my head, but I remember Bjarne Stroustrup saying (on a few occasions, in a talk or a panel) that "non-type template parameters were introduced in C++ over the dead bodies of some type theorists" (quote from memory). This surprises me since types depending on values is a fundamental concept in Martin-Löf type theory which is older than C++. Does anyone have any knowledge on what feedback Bjarne Stroustrup received from type theorists? submitted by /u/dylanzdavies
[link] [comments]
C++ – Типизированный язык программирования
[Из песочницы] Кривые Безье. Немного о пересечениях и как можно проще

Article

Вы сталкивались когда-нибудь с построением (непрерывного) пути обхода кривой на плоскости, заданной отрезками и кривыми Безье?

Вроде бы не сильно сложная задача: состыковать отрезки кривых в один путь и обойти его "не отрывая пера". Замкнутая кривая обходится в одном направлении, ответвления — в прямом и обратном, начало и конец в одном узле.

Всё было хорошо, пока из-под рук дизайнеров не стали вылезать монструозные пути, где отдельные кривые могли пересекаться или не точно состыковываться. Объяснение было предельно простым — визуально они все лежат как надо, а для станка, который этот путь будет обходить, такие отклонения незаметны.

Вооружившись знанием о величине максимально допустимого отклонения, я приступил к исследованию, результатами которого хочу поделиться. Читать дальше →
Arthur O’Dwyer
A very short war story on too much overloading

On my previous post
“Inheritance is for sharing an interface (and so is overloading)” (2020-10-09),
a couple of Reddit commenters expressed disbelief at my third section, where I claimed that the
vector::erase overload set was poorly designed. They had never run into the common bug

// Oops!
v.erase(
std::remove_if(v.begin(), v.end(), isOdd)
);


For more on erasing from STL containers, see “How to erase from an STL container” (2020-07-08).

Here’s another example of grief caused by overuse-of-overloading, which I just ran into at work last week.

class mgr_t : public asio_actor {
~~~
virtual std::string getname() const = 0;
virtual result_t subscribe(actor::ptr tgt, msghandler handler,
priority::level prio, const std::string type,
bool enrich = false) = 0;
virtual result_t subscribe(actor::ptr tgt, msghandler handler,
priority::level prio, selector f, unsigned &id,
bool enrich = false) = 0;
virtual result_t subscribe(actor::ptr tgt, msghandler handler,
priority::level prio,
bool enrich = false) = 0;
virtual void subscribe_connect(actor::ptr tgt, connhandler handler,
priority::level prio) = 0;
virtual void subscribe_disconnect(actor::ptr tgt, connhandler handler,
priority::level prio) = 0;
~~~
};


And then there’s a caller in some other repository that does this:

this->message_ = std::string("subscription failed");
return g_mgr->subscribe(ctl_actor::instance(), stats,
priority::level::high, std::string("queue-stats"));


You might look at those lines and think: Ah, the casts to std::string are redundant. This is just
a Java programmer’s attempt to keep track of where “string objects” are created. I can remove them.

You’d be right about the first cast, but it turns out you’d be wrong about the second!

return g_mgr->subscribe(ctl_actor::instance(), stats,
priority::level::high, std::string("queue-stats"));


is a call to mgr_t::subscribe(actor::ptr, msghandler, priority::level, const std::string, bool = false). But

return g_mgr->subscribe(ctl_actor::instance(), stats,
priority::level::high, "queue-stats");


is a call to mgr_t::subscribe(actor::ptr, msghandler, priority::level, bool = false)!
Because "queue-stats", after decaying to const char*, would rather implicitly convert
to the built-in type bool than to the user-defined type std::string. (Godbolt.)

The above snippet exemplifies many sins which I’ve previously discussed on this blog. See:



“Default function arguments are the devil” (2020-04-18)


const is a contract” (2019-01-03) re the missing ampersand


“PSA: shared_ptr() is not make_shared()” (2019-03-06) re actor::ptr


And of course it should be using the Non-Virtual Interface idiom, but I haven’t got a blog post
dedicated to that subject, yet. See
“CppCon 2019 talks are up” (2019-10-18).



Nevertheless, I think the primary sin here — or at least the “first among equals
— is that it has three overloads of subscribe, doing radically different things with (s
C++
CppCon 2020 presentation recommendations?

I've seen four videos so far and I can only recommend one of them as being interesting and/or well presented: The Many Shades of reference_wrapper - Zhihao Yuan - CppCon 2020 Do you guys have recommendations? submitted by /u/lookatmetype
[link] [comments]