【发布时间】:2021-10-04 16:46:42
【问题描述】:
给定一个矩阵模板类mat<M,N,T>,以下成员函数允许我有效地转置行向量或列向量,因为它们具有相同/对应的内存占用:
template<int M, int N=M, typename T = double>
struct mat {
// ...
template<int Md = M, int Nd = N, typename = std::enable_if_t<Md == 1 || Nd == 1>>
const mat<N, M, T>& transposedView() const {
static_assert(M == 1 || N == 1, "transposedView() supports only vectors, not general matrices.");
return *reinterpret_cast<const mat<N, M, T>*>(this);
}
}
多年来我一直在使用这个函数,出于习惯开始在临时表达式 (/*vector-valued expression*/).transposedView() 上调用它,忘记了它会返回对临时的引用,并导致 GCC 只是咬我的未定义行为。
是否有一种简单的方法可以让我添加一些在我临时调用它时会产生某种警告的东西?
或者,只要我不存储引用,临时调用它实际上应该是安全的吗?
【问题讨论】:
-
该策略具有未定义的行为。幸运的是它没有停止工作或随机破坏您的程序。
-
您可以overload on lvalueness/rvalueness 获取类成员函数。您可以声明和删除右值版本。
-
@FrançoisAndrieux 即使我不存储返回的引用而只立即使用它?
-
@Museful 是的。您正在创建一个指向
mat<N, M, T>的指针,其中没有这样的对象(除非M和N都是 1)。然后,取消引用该指针违反了type aliasing 规则。基本上,编译器将假定返回的指针指向与this不同的对象,因为它们指向不同的类型。有时,这不会导致问题,但编译器可能会在尝试优化时破坏代码的行为。 -
@Museful 是的,在这种情况下,取消引用
reinterpret_cast会自动成为未定义行为(同样,除非mat<N,M,T>与mat<M,N,T>的类型相同)。一般来说,如果reinterpret_cast似乎解决了一个问题,它可能没有。大多数情况下,您唯一能做的就是将某些东西转换回其真正的原始类型。
标签: c++ c++17 temporary-objects