c++ - CRTP - 危险的内存访问?

标签 c++

我创建了以下测试代码来试验 Curiously Recurring Template Pattern ,其中我有一个带有 Interface()Base 类和一个带有 ImplementationDerived 类。它直接根据链接的维基百科页面中最简单的示例建模。

#include <iostream>

template <class T>
class Base {
 public:
  void Interface() {
    std::cout << "Base Interface()" << std::endl;
    static_cast<T*>(this)->Implementation();
  }
};

class Derived : public Base<Derived> {
 public:
  Derived(int data = 0) : data_(data) {}

  void Implementation() {
    std::cout << "Derived Implementation(), data_ = " << data_ << std::endl;
  }

 private:
  int data_;
};

int main() {
  Base<Derived> b;
  b.Interface();
  std::cout << std::endl;

  Derived d;
  d.Interface();
  std::cout << std::endl;

  return 0;
}

编译后,程序运行顺利并产生以下输出:

Base Interface()
Derived Implementation(), data_ = -1450622976

Base Interface()
Derived Implementation(), data_ = 0

有趣的部分是第一个测试,其中 Base 指针被转换为 Derived 指针,函数 Implementation() 正在被调用。在该函数内部,正在访问一个“成员变量”data_

对我们来说这是无稽之谈,但对编译器来说它只是该对象内存位置的某个偏移量的值。但是,在这种情况下,Derived 类比基类占用更多空间,因此如果编译器认为它正在从 Derived 对象访问数据成员,但实际上是对象是一个Base对象,那么我们正在访问的内存可能不属于这个对象,甚至不属于这个程序。

似乎这种编程习惯让我们(程序员)很容易做出非常危险的事情,比如进行看似合理的函数调用,但最终却从不受控制的内存位置读取数据。我是否正确解释了这个例子的机制?如果是这样,我是否错过了 CRTP 范例中的一些技术来确保不会出现此问题?

最佳答案

一般情况下,如果您传递的指针指向一个对象,该对象在其继承层次结构中某处包含目标类,则 static_cast 可以正常工作。

为了
基地 b; b.接口(interface)();

一个指向真实Base对象的指针被传递给static_cast,它与Derived类完全无关。所以在转换之后你有一个指针看起来像一个指向 Derived 的指针,但它仍然指向内存中的一个 Base 对象。当您通过该指针访问 data_ 成员时,您将获得内存中某个未初始化区域的内容。

关于c++ - CRTP - 危险的内存访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52599394/

相关文章:

c++ - 删除要从 vector 中删除的指针

c++ - 定义我自己的新运营商

c++ - 为什么 std::optional::value() &&;返回 &&?

C++ odbc 关闭记录集泄漏内存

c++ - MD、LD等代表什么?

c++ - IDE 的最兼容的 C++ Doxygen 注释

c++ - 反编译混淆的dll

c++ - `bit_cast` 数组到数组

c++ - 库使用的模板实例化

C++ - 使用 'i' 检查 for 循环中的不同变量