为什么返回值与优化标志不正确?



我正在(只为我自己)练习c++并试图"重新编码";c#属性。我知道这是没用的(我的意思是,我不会使用它)然而,我只是想尝试看看这是否可能。

由于某些原因,使用以下代码,在最新的clang/gcc版本下,除了-O0(据我所知,它禁用了优化)之外,它并没有在每个优化标志下产生正确的结果。

#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;
}

它似乎在visual studio编译器下表现正确,但我不确定。

我是否错过了标准的一部分?我的代码不正确吗?clang/gcc/STL有bug吗?

我把我的代码放在一个叫Godbolt的网站上,以便在编译器之间轻松切换,但我得到了同样不连贯的结果。

下面是c++14/clang 14的打印内容:

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
624203080

最后一个数字在运行之间变化,但不是第一个,使我认为它只是使用未初始化的数据

您的问题是这部分:using getType = std::function<const T&(void)>;get{[this] () { return internal; }}结合。

lambda在这里不返回internal作为引用,因此返回internal的副本,并且-在这里我不知道std::function是如何实现的-std::function必须持有internal的副本,但返回它作为对该副本的引用,而不是悬空。

将其更改为get{[this] () -> T& { return internal; }}似乎可以解决问题。

初始化get的lambda按值返回,而不是按引用返回,这意味着返回的int不再存在于std::function机制中的某个地方。

你可以指定一个引用返回

[this] () -> const T& { return internal; }

的被害者。你应该使Property不可复制和不可移动,因为你不能在复制或移动std::function成员时重新指向this捕获。

最新更新