I am (for myself only) practicing c and trying to "re-code" c# properties into it. I do know it is useless (I mean, I will not use it) however, I just wanted to try to see if this was possible.
For some reasons, with the following code, under the latest clang / gcc version, it does not yeld the correct result under every single optimisation flags other than -O0
(which disables optimisation as far as I am aware of.)
#include <functional>
#include <iostream>
template<typename T>
class Property
{
private:
using getType = std::function<const T&(void)>;
using setType = std::function<void(const T&)>;
T internal;
getType get;
setType set;
public:
Property(const T &value) : internal{value}, get{[this] () { return internal; }}, set{[this](const T& value) { internal = value; }} {}
Property(getType fnc) : get(fnc) { }
Property(getType fncGet, setType fncSet) : get(fncGet), set(fncSet) { }
Property(setType fnc) : set(fnc) { }
Property(setType fncSet, getType fncGet) : get(fncGet), set(fncSet) { }
Property<T> &operator=(T& value) { set(value); return *this; }
operator const T&() const { return get(); }
};
int main(void)
{
Property<int> hey(12);
std::cout << hey << std::endl;
return hey;
}
It seems to behave correctly under visual studio compiler but i'm unsure.
Have I missed a part of the standard? Is my code incorrect? is there a bug in clang / gcc / the STL?
I placed my code on the website called Godbolt to switch easily between compilers and I had the same incoherent results.
Here is what it prints me for c 14 / clang 14:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
624203080
The last number changes between runs, but not the first one making me think it just takes uninitialized data.
CodePudding user response:
Your problem is this part: using getType = std::function<const T&(void)>;
in combination with get{[this] () { return internal; }}
.
The lambda does not return the internal
as a reference here, so a copy of internal
is returned, and - here I don't know how std::function
is implemented - std::function
has to hold a copy of internal
but returns it as a reference to that copy which is than dangling.
Changing it to get{[this] () -> T& { return internal; }}
seems to solve the problem.
CodePudding user response:
The lambda you initialise get
with returns by value, not by reference, which means that the returned int
ceases to exist somewhere in the std::function
machinery.
You can specify a reference return
[this] () -> const T& { return internal; }
N.b. you should make Property
uncopyable and immovable, as you can't re-point the this
capture within the std::function
members when copying or moving.