Date: Mon, 28 Apr 2025 09:32:18 +0200
On 28/04/2025 7:56 am, Tiago Freire via Std-Discussion wrote:
> I’m not convinced by this example. I have written many callback systems
> and never has “uniqueness” been relevant.
>
> Is that a good design? Or one that can’t be improved upon?
>
> Had C++ not provided this guarantee all along, would the algorithm (in
> the context of its intended end use) be undesignable?
>
> As mentioned, the only reason it would make a difference is because you
> are trying to do logic related to the function beyond “it exists, and it
> is callable”, and whatever that is there’s probably a better solution to
> be found elsewhere.
>
> In this case, what you want is a unique token and absent a feature for
> that you used an unrelated “this function address is unique” to achieve
> that.
>
> I’m not saying that maybe it isn’t necessary in this case, I don’t see
> the concrete example you might have in mind.
If anyone has a suggestion how the concrete example I have provided can
be improved, I'm all ears.
But the problem appears in other context too:
struct T{int i;};
T* get1(void* ptr){ return start_lifetime_as<T>(ptr);}
T* get2(void* ptr){ return reinterpret_cast<T>(ptr);}
T* get3(void* ptr){ return std::launder(reinterpret_cast<T>(ptr));}
get1/get2/get3 might generate the same code, but it is not possible to
use one instead of another.
> But if the address being unique is important for this function, wouldn’t
> it be better to explicit request it with a tag [[unique_address]] and
> not make it the default everywhere?
Attributes can be ignored.
The correctness of a program should not rely on something that can be
ignored.
> *From:*Tom Honermann <tom_at_[hidden]>
> *Sent:* Monday, April 28, 2025 6:08 AM
> *To:* std-discussion_at_[hidden]
> *Cc:* Tiago Freire <tmiguelf_at_[hidden]>
> *Subject:* Re: [std-discussion] Guarantees over addresses from function
> pointers created from lambda
>
> On 4/27/25 6:53 AM, Tiago Freire via Std-Discussion wrote:
>
> > I'm not sure how you could do that other than maybe dropping
> function pointer comparison altogether except against nullptr.
>
> I don't see a reason not to do that.
>
> Comparisons can be useful to support callback function registration
> systems. Designs that use the function pointer itself as the
> registration key depend on registered functions having exactly one
> unique address assigned to them.
>
> Tom.
>
> ------------------------------------------------------------------------
>
> *From:* Std-Discussion <std-discussion-bounces_at_[hidden]>
> <mailto:std-discussion-bounces_at_[hidden]> on behalf of
> Jennifier Burnett via Std-Discussion <std-
> discussion_at_[hidden]> <mailto:std-discussion_at_[hidden]>
> *Sent:* Sunday, April 27, 2025 12:06:36 PM
> *To:* std-discussion_at_[hidden] <mailto:std-
> discussion_at_[hidden]> <std-discussion_at_[hidden]>
> <mailto:std-discussion_at_[hidden]>; Nate Eldredge via Std-
> Discussion <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]>
> *Cc:* Jennifier Burnett <jenni_at_[hidden]>
> <mailto:jenni_at_[hidden]>
> *Subject:* Re: [std-discussion] Guarantees over addresses from
> function pointers created from lambda
>
> I have worked on one codebase that something did this, for basically
> the same reason as the original example in this thread where they
> were rolling their own vtables for a type erased callback storage
> class, and they used a sentinel function to identify trivially
> copyable and trivially destructible classes to skip the function
> call. Nullptr was used to indicate an empty callback.
>
> In both cases there were branch mispredictions happening on the
> check for the sentinel (plus additional instructions were needed to
> form the sentinel address) and it was just faster to call an empty
> function for the trivial destructor and have the trivial copy just
> use a function that called memcpy. The original company as far as
> I'm aware didn't merge our changes back into their codebase.
>
> I've also worked on a different codebase which was using a function
> pointer to a templated function as a form of cheap RTTI on a type
> erased container (games, so nobody ships codebases with it enabled).
>
> Ideally if it was dropped you'd want existing code relying on it to
> break at compile time, I'm not sure how you could do that other than
> maybe dropping function pointer comparison altogether except against
> nullptr.
>
> On 27 April 2025 03:49:37 BST, Nate Eldredge via Std-Discussion
> <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]> wrote:
>
> On Apr 26, 2025, at 11:34, Andrey Semashev via Std-Discussion
> <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]> wrote:
>
>
> The point is, even if the standard guarantees this [pointers
> to different functions comparing unequal], it's probably not a
> good idea to rely on this in practice.
>
> This being so, does anyone know if there has ever been a formal
> proposal to weaken this rule, or informal study of doing so?
>
> I can certainly see the aesthetic argument for the rule, but I
> wonder how much real-life code actually relies on it. The only
> specific use case I can see is sentinels:
>
> void sentinel() { }
>
> void foo(void (*callback)()) {
>
> if (!callback) {
>
> proceed_without_callback();
>
> } else if (callback == sentinel) {
>
> something_special();
>
> } else {
>
> callback();
>
> }
>
> }
>
> but it seems like a modern C++ programmer would rather do that
> with std::variant <std::variant> or some other way. So I wonder
> if anyone has studied the impact on existing code bases of
> dropping this guarantee.
>
>
>
>
> I’m not convinced by this example. I have written many callback systems
> and never has “uniqueness” been relevant.
>
> Is that a good design? Or one that can’t be improved upon?
>
> Had C++ not provided this guarantee all along, would the algorithm (in
> the context of its intended end use) be undesignable?
>
> As mentioned, the only reason it would make a difference is because you
> are trying to do logic related to the function beyond “it exists, and it
> is callable”, and whatever that is there’s probably a better solution to
> be found elsewhere.
>
> In this case, what you want is a unique token and absent a feature for
> that you used an unrelated “this function address is unique” to achieve
> that.
>
> I’m not saying that maybe it isn’t necessary in this case, I don’t see
> the concrete example you might have in mind.
If anyone has a suggestion how the concrete example I have provided can
be improved, I'm all ears.
But the problem appears in other context too:
struct T{int i;};
T* get1(void* ptr){ return start_lifetime_as<T>(ptr);}
T* get2(void* ptr){ return reinterpret_cast<T>(ptr);}
T* get3(void* ptr){ return std::launder(reinterpret_cast<T>(ptr));}
get1/get2/get3 might generate the same code, but it is not possible to
use one instead of another.
> But if the address being unique is important for this function, wouldn’t
> it be better to explicit request it with a tag [[unique_address]] and
> not make it the default everywhere?
Attributes can be ignored.
The correctness of a program should not rely on something that can be
ignored.
> *From:*Tom Honermann <tom_at_[hidden]>
> *Sent:* Monday, April 28, 2025 6:08 AM
> *To:* std-discussion_at_[hidden]
> *Cc:* Tiago Freire <tmiguelf_at_[hidden]>
> *Subject:* Re: [std-discussion] Guarantees over addresses from function
> pointers created from lambda
>
> On 4/27/25 6:53 AM, Tiago Freire via Std-Discussion wrote:
>
> > I'm not sure how you could do that other than maybe dropping
> function pointer comparison altogether except against nullptr.
>
> I don't see a reason not to do that.
>
> Comparisons can be useful to support callback function registration
> systems. Designs that use the function pointer itself as the
> registration key depend on registered functions having exactly one
> unique address assigned to them.
>
> Tom.
>
> ------------------------------------------------------------------------
>
> *From:* Std-Discussion <std-discussion-bounces_at_[hidden]>
> <mailto:std-discussion-bounces_at_[hidden]> on behalf of
> Jennifier Burnett via Std-Discussion <std-
> discussion_at_[hidden]> <mailto:std-discussion_at_[hidden]>
> *Sent:* Sunday, April 27, 2025 12:06:36 PM
> *To:* std-discussion_at_[hidden] <mailto:std-
> discussion_at_[hidden]> <std-discussion_at_[hidden]>
> <mailto:std-discussion_at_[hidden]>; Nate Eldredge via Std-
> Discussion <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]>
> *Cc:* Jennifier Burnett <jenni_at_[hidden]>
> <mailto:jenni_at_[hidden]>
> *Subject:* Re: [std-discussion] Guarantees over addresses from
> function pointers created from lambda
>
> I have worked on one codebase that something did this, for basically
> the same reason as the original example in this thread where they
> were rolling their own vtables for a type erased callback storage
> class, and they used a sentinel function to identify trivially
> copyable and trivially destructible classes to skip the function
> call. Nullptr was used to indicate an empty callback.
>
> In both cases there were branch mispredictions happening on the
> check for the sentinel (plus additional instructions were needed to
> form the sentinel address) and it was just faster to call an empty
> function for the trivial destructor and have the trivial copy just
> use a function that called memcpy. The original company as far as
> I'm aware didn't merge our changes back into their codebase.
>
> I've also worked on a different codebase which was using a function
> pointer to a templated function as a form of cheap RTTI on a type
> erased container (games, so nobody ships codebases with it enabled).
>
> Ideally if it was dropped you'd want existing code relying on it to
> break at compile time, I'm not sure how you could do that other than
> maybe dropping function pointer comparison altogether except against
> nullptr.
>
> On 27 April 2025 03:49:37 BST, Nate Eldredge via Std-Discussion
> <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]> wrote:
>
> On Apr 26, 2025, at 11:34, Andrey Semashev via Std-Discussion
> <std-discussion_at_[hidden]> <mailto:std-
> discussion_at_[hidden]> wrote:
>
>
> The point is, even if the standard guarantees this [pointers
> to different functions comparing unequal], it's probably not a
> good idea to rely on this in practice.
>
> This being so, does anyone know if there has ever been a formal
> proposal to weaken this rule, or informal study of doing so?
>
> I can certainly see the aesthetic argument for the rule, but I
> wonder how much real-life code actually relies on it. The only
> specific use case I can see is sentinels:
>
> void sentinel() { }
>
> void foo(void (*callback)()) {
>
> if (!callback) {
>
> proceed_without_callback();
>
> } else if (callback == sentinel) {
>
> something_special();
>
> } else {
>
> callback();
>
> }
>
> }
>
> but it seems like a modern C++ programmer would rather do that
> with std::variant <std::variant> or some other way. So I wonder
> if anyone has studied the impact on existing code bases of
> dropping this guarantee.
>
>
>
>
Received on 2025-04-28 07:32:25