Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe to pass empty variables by value, when they have no definition?

If I pass an empty variable by value, even though it has no definition, is it safe and compliant?

I came across this issue while working on code, overloading |, to make this print the contents of the vector v:

v | print; // prints the vector v

The code I present here works for me with g++ and clang, even though print is an extern variable with no linkage, but I wonder if I'm pushing the standard too far. This is for c++11/c++14, I guess this is solved in c++17 with inline variables?

First, my initial code. The goal is to allow things like v|print to print a vector. I have bigger goals too, related to ranges, but I'll focus on this tiny example here

struct print_tag_t {};

print_tag_t print;

void operator| (std::vector<int> & x, decltype(print) ) {
    for(auto elem : x) {
        std::cout << elem << '\n';
    }
}

int main() {
    std::vector<int>  v{2,3,5,7};
    v | print;
}

Moving this to a header

If I move this into a header, I can make the operator| overload as inline. But what about print? I have found that I can make it extern to avoid the linker error about duplicate symbols

// print.hh
struct print_tag_t {};

extern  // extern, as I can't use inline on a variable
print_tag_t print;

inline
void operator| (std::vector<int> & x, decltype(print) ) {
    for(auto elem : x) {
        std::cout << elem << '\n';
    }
}

This works for me. Somehow, even though print has no definition, I can do v|print. I guess it's because it's empty and therefore there is no value to inspect and therefore it never needs an address.

Are compilers required to allow my v|print example to work? Where, to clarify, print is extern and hasn't been given any definition?

like image 537
Aaron McDaid Avatar asked Nov 02 '17 11:11

Aaron McDaid


People also ask

How do you pass an empty variable in Python?

Defining Empty Variables with None and NaN Defining empty variables in Python is straightforward. If you wish to define a placeholder for a missing value that will not be used for calculations, you can define an empty variable using the None keyword.

What does it mean for a variable to be empty?

A variable is considered empty if it does not exist or if its value equals false .

Is null == undefined?

It means null is equal to undefined but not identical. When we define a variable to undefined then we are trying to convey that the variable does not exist . When we define a variable to null then we are trying to convey that the variable is empty.

What is the benefit of setting a variable to null when you no longer need it?

Explicitly assigning a null value to variables that are no longer needed helps the garbage collector to identify the parts of memory that can be safely reclaimed.


1 Answers

Are compilers required to allow my v|print example to work? Where, to clarify, print is extern and hasn't been given any definition?

No. You are odr-using print (you're invoking an lvalue-to-rvalue conversion that doesn't yield a constant expression), which means you need a definition for print. However, this is one of the categories of error that are ill-formed, no diagnostic required. And since the code in question doesn't take the address of print anywhere, it's likely that the compiler will emit code that will not require such a definition, and hence the linker will be happy about it too. Typically, it will Just Work™.

A better solution would be to simply change the declaration to make print constexpr:

constexpr print_tag_t print{};

Now, v | print wouldn't odr-use print (since the lvalue-to-rvalue conversion would now be a constant expression), so no definition is even necessary, so the program is well-formed.

like image 83
Barry Avatar answered Oct 29 '22 05:10

Barry