Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal linkage variables in uri.hpp #1146

Open
lenard-mosys opened this issue Sep 30, 2024 · 0 comments
Open

internal linkage variables in uri.hpp #1146

lenard-mosys opened this issue Sep 30, 2024 · 0 comments

Comments

@lenard-mosys
Copy link

Hi, I just spotted the following

// TODO: figure out why this fixes horrible linking errors.
/// Default port for ws://
static uint16_t const uri_default_port = 80;
/// Default port for wss://
static uint16_t const uri_default_secure_port = 443;

As for answering the question stated in the comment:

Not sure what the original code was, but could have been something like extern uint16_t const uri_default_port = 80, which leads to linking errors if multiple translation units include the header, as there can only be one definition of the single entity uri_default port.

static uint16_t const uri_default_port or just uint16_t const uri_default_port (const implies static here, don't ask why) makes each translation unit have their own uri_default_port variable.

Some usual workarounds of the original problem:

  1. From C++17, you can have inline variables (I believe that's not an option), these generate weak symbols for the variables:
inline uint16_t const uri_default_port = 80;
inline uint16_t const uri_default_secure_port = 443;
  1. You can emulate C++17 inline variables with static members of class templates, then you can assign them to namespace-scope static references (boost itself uses this pattern at places). This is very cumbersome, but works:
template <typename = void>
struct uri_default_ports {
    static const uint16_t insecure;
    static const uint16_t secure;
};

template <typename T>
const uint16_t uri_default_ports<T>::insecure = 80;

template <typename T>
const uint16_t uri_default_ports<T>::secure = 443;

static const uint16_t& uri_default_port = uri_default_ports<>::insecure;
static const uint16_t& uri_default_secure_port = uri_default_ports<>::secure;
  1. You can use the "enum hack", the trade-off is that you can't take the address of these, which is potentially breaking. And specifying the underlying type is not available before C++11, if you care about that.
enum uri_default_ports {
    uri_default_port = 80,
    uri_default_secure_port = 443
};
  1. Leave as is. Use of these variables in inline functions (as you already do) might open the door of ODR-violations, if the address of these variables are taken (they get odr-used), as you have distinct entities in distinct translation units for these variables. I don't think you actually have this issue, but your user might. In any case, I don't think a typical ODR-violation with these variables would manifest in an actual bug.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant