Date: Sun, 11 May 2025 23:54:07 -0400
On 4/28/25 1: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?
>
It doesn't much matter whether it is a good design because it exists in
practice. Consider atexit() and pthread_atfork(). While not
standardized, some implementations offer interfaces to unregister
previously registered functions. For example, AIX allows unregistering
functions via unatexit() and pthread_atfork_unregister_np() interfaces.
> 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.
>
See above.
> 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?
>
Perhaps, but it would be a breaking change now.
Tom.
> *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]
> <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 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?
>
It doesn't much matter whether it is a good design because it exists in
practice. Consider atexit() and pthread_atfork(). While not
standardized, some implementations offer interfaces to unregister
previously registered functions. For example, AIX allows unregistering
functions via unatexit() and pthread_atfork_unregister_np() interfaces.
> 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.
>
See above.
> 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?
>
Perhaps, but it would be a breaking change now.
Tom.
> *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]
> <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 or some other way. So I wonder if anyone
> has studied the impact on existing code bases of dropping this
> guarantee.
>
>
>
>
Received on 2025-05-12 03:54:15