C++ 优化破坏存储引用的代码
C++ Optimization Breaking Code That Stores References
我 运行 遇到了一个问题,我的代码在没有优化的情况下工作正常,但在启用优化时会中断。经过大量调查,我找到了代码中断的地方。看来这个问题与我使用参考文献有关。
我有一个简单的class如下:
template<typename T, typename U>
class DoubleValueEvent {
public:
DoubleValueEvent(const T& v0, const U& v1) : _v0(v0), _v1(v1) {}
//Move version of the constructor
DoubleValueEvent(const T&& v0, const U&& v1) : _v0(v0), _v1(v1) {}
inline const T& value0() const { return _v0; }
inline const U& value1() const { return _v1; }
private:
const T& _v0;
const U& _v1;
};
我的值(v0 和 v1)存储为引用,因为对于我的应用程序,此对象充当现有变量的包装器,并且对象的生命周期仅与变量本身一样长。
这是我如何使用它的示例:
void myFunction(int a, bool b) {
DoubleValueEvent<int,bool> e(a,b);
//This functions uses e but never stores it
foo(&e);
}
这一直很好用,避免了不必要的数据处理。但是,它在以下情况下中断:
static inline int convert(int milliseconds) {
return milliseconds / 1000;
}
void mySecondFunction(int a, bool b) {
DoubleValueEvent<int,bool> e(convert(a),b);
//Breakpoint here shows the stored value for the int to be garbage
foo(&e);
}
如果我在调用 foo() 时放置一个断点,我可以看到存储在 e 中的引用值是一些垃圾值,而不是我所期望的值。
我推测发生的事情是我的 DoubleValueEvent 构造函数没有正确地“移动”来自 convert() 的临时 return 值,因此编译器正在优化这个值,但我不确定。
有什么建议吗?
谢谢!
您走在正确的轨道上:您的右值引用构造函数没有正确“移动”值。事实上,从移动构造值的意义上说,它根本没有移动它。
这是有道理的。您尚未定义将其移动到 到 的任何位置。您的 class 包含几个引用,但无处存储它们。该行代码完成后,int belong 是什么?
您似乎正试图从 Most Important Const 的某些变体中获益,其中绑定到 const 引用的临时对象的生命周期在对象的生命周期内持续存在。但这仅适用于局部范围的引用,不适用于 class.
中的引用
如您所说,“此对象充当现有变量的包装器”。但是在有问题的情况下,没有变量可以包装,只是临时变量。
class 可以存储传递给其构造函数的左值引用,但您需要非常非常小心。 class 不能存储传递给其构造函数的右值引用,包括将它们存储为左值引用。它是右值引用这一事实意味着它即将消失。
我 运行 遇到了一个问题,我的代码在没有优化的情况下工作正常,但在启用优化时会中断。经过大量调查,我找到了代码中断的地方。看来这个问题与我使用参考文献有关。
我有一个简单的class如下:
template<typename T, typename U>
class DoubleValueEvent {
public:
DoubleValueEvent(const T& v0, const U& v1) : _v0(v0), _v1(v1) {}
//Move version of the constructor
DoubleValueEvent(const T&& v0, const U&& v1) : _v0(v0), _v1(v1) {}
inline const T& value0() const { return _v0; }
inline const U& value1() const { return _v1; }
private:
const T& _v0;
const U& _v1;
};
我的值(v0 和 v1)存储为引用,因为对于我的应用程序,此对象充当现有变量的包装器,并且对象的生命周期仅与变量本身一样长。
这是我如何使用它的示例:
void myFunction(int a, bool b) {
DoubleValueEvent<int,bool> e(a,b);
//This functions uses e but never stores it
foo(&e);
}
这一直很好用,避免了不必要的数据处理。但是,它在以下情况下中断:
static inline int convert(int milliseconds) {
return milliseconds / 1000;
}
void mySecondFunction(int a, bool b) {
DoubleValueEvent<int,bool> e(convert(a),b);
//Breakpoint here shows the stored value for the int to be garbage
foo(&e);
}
如果我在调用 foo() 时放置一个断点,我可以看到存储在 e 中的引用值是一些垃圾值,而不是我所期望的值。
我推测发生的事情是我的 DoubleValueEvent 构造函数没有正确地“移动”来自 convert() 的临时 return 值,因此编译器正在优化这个值,但我不确定。
有什么建议吗?
谢谢!
您走在正确的轨道上:您的右值引用构造函数没有正确“移动”值。事实上,从移动构造值的意义上说,它根本没有移动它。
这是有道理的。您尚未定义将其移动到 到 的任何位置。您的 class 包含几个引用,但无处存储它们。该行代码完成后,int belong 是什么?
您似乎正试图从 Most Important Const 的某些变体中获益,其中绑定到 const 引用的临时对象的生命周期在对象的生命周期内持续存在。但这仅适用于局部范围的引用,不适用于 class.
中的引用如您所说,“此对象充当现有变量的包装器”。但是在有问题的情况下,没有变量可以包装,只是临时变量。
class 可以存储传递给其构造函数的左值引用,但您需要非常非常小心。 class 不能存储传递给其构造函数的右值引用,包括将它们存储为左值引用。它是右值引用这一事实意味着它即将消失。