【问题标题】:Generating a warning when a member function is invoked on a temporary object在临时对象上调用成员函数时生成警告
【发布时间】: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&lt;N, M, T&gt; 的指针,其中没有这样的对象(除非 MN 都是 1)。然后,取消引用该指针违反了type aliasing 规则。基本上,编译器将假定返回的指针指向与this 不同的对象,因为它们指向不同的类型。有时,这不会导致问题,但编译器可能会在尝试优化时破坏代码的行为。
  • @Museful 是的,在这种情况下,取消引用 reinterpret_cast 会自动成为未定义行为(同样,除非 mat&lt;N,M,T&gt;mat&lt;M,N,T&gt; 的类型相同)。一般来说,如果reinterpret_cast 似乎解决了一个问题,它可能没有。大多数情况下,您唯一能做的就是将某些东西转换回其真正的原始类型。

标签: c++ c++17 temporary-objects


【解决方案1】:

会员功能可以是qualified for lvalue or rvalue objects。使用它,您可以创建一个重载集,如

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);
    }
    template<int Md = M, int Nd = N, typename = std::enable_if_t<Md == 1 || Nd == 1>>
    const mat<N, M, T>& transposedView() && const = delete;
}

现在如果你尝试用右值对象调用函数,你会得到一个编译器错误。

【讨论】:

  • 事实证明,即使在 l 值上调用它在技术上也是 UB。但你回答的正是我问的问题。
猜你喜欢
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
  • 2012-04-20
  • 2015-05-01
  • 2014-08-07
相关资源
最近更新 更多