C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Callsite passed as template parameter

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Fri, 17 Nov 2023 01:43:03 +0100
pt., 17 lis 2023 o 00:44 Frederick Virchanza Gotham via Std-Proposals
<std-proposals_at_[hidden]> napisaƂ(a):
>
> On Thu, Nov 16, 2023 at 8:38 PM Marcin Jaczewski wrote:
> >
> > Are you aware that the thing you propose is opposite of this?
> > Do you know that each function `static` needs lock and it's not free.
> > Or at least condition variable to check if the value was already initialized.
>
>
> Not sure what you're saying here as your post is a bit vague, but if
> you're referring to how since C++11 we've been guaranteed that
> static-duration variables inside functions are thread-safe, and that
> we therefore need a lock for each static variable inside a function,
> well then let's just explore that -- consider the following code:
>
> #include <string> // string
> std::string &Func(char const c)
> {
> static std::string str(c, 20u);
> return str;
> }
>
> This code will behave exactly as though you had written:
>
> #include <mutex> // call_once, once_flag
> #include <optional> // optional
> #include <string> // string
> std::once_flag myflag;
> std::optional<std::string> optional_str;
> std::string &Func(char const c)
> {
> std::call_once(myflag, [c]{ optional_str.emplace(c, 20u); });
> std::string &str = optional_str.value();
> return str;
> }
>
> Ando so yes there's overhead here -- we have a lock. But that's only
> because the constructor for std::string is complicated. Let's consider
> a much more simple example:
>
> int &Func(void)
> {
> static int i = 77;
> return i;
> }
>
> This will simply get compiled to:
>
> constinit int i = 77;
>
> int &Func(void)
> {
> return i;
> }
>
> If we were to make it a little more complicated, then we would need a
> lock, for example:
>
> int &Func(int const arg)
> {
> static int i = arg / 2;
> return i;
> }
>
> would get compiled to:
>
> #include <mutex> // call_once, once_flag
> std::once_flag myflag;
> int i;
> int &Func(int const arg)
> {
> std::call_once(myflag, [arg]{ i = arg / 2; });
> return i;
> }
>
> In my original example code that I gave in a previous post, I had a
> char buffer that got initialised to all zeroes as follows:
>
> #include <cstring> // memcpy
> #include <algorithm> // min
> #include <string_view> // string_view
> template <typename = decltype([]{})>
> char const *cstr(std::string_view const sv)
> {
> static char buf[64u] = {};
> std::size_t const len = std::min(sizeof buf - 1u, sv.size());
> if ( len ) std::memcpy(buf, &sv.front(), len);
> buf[len] ='\0';
> return buf;
> }
>
> There's no need for any lock here, the buffer will be get set to all
> zeroes before the function is ever entered.
>

Ok,
and do you check other compilers too?
Because if you propose something you should check
how it will affect all major compiers and possible future ones.
What limitations and drawbacks it has.

>
> > In many cases a lot better would be pure `std::array` (or static vector)
> > on stack and have a bigger stack to accommodate all data like this.
> > This would have another benefits that program will not waste memory
> > for things that are used only in one case and many "cases" have no
> > overlapping lifetime.
>
>
> Again not sure what you're saying here. I prefer to waste memory on
> microcontrollers instead of using dynamic allocation. If I had my way,
> my microcontrollers would have no heap.

Where did I said something about dynamic allocation?
If you referring to "static vector" then you are wrong:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0843r2.html
Or any other similar data structure.
Alternative there is `std::pmr` that can be easily backed by static storage.
And you can use it with `std::string` and `std::vector` and
no dynamic allocation anywhere in your code after that.


> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2023-11-17 00:43:15