【问题标题】:Are C++ functions in classes dynamically allocated?类中的 C++ 函数是动态分配的吗?
【发布时间】:2013-10-16 17:30:50
【问题描述】:
class myclass{
 public: void hello(){
   std::cout<<"Hello"<<"\n";
 }
}
myclass* mc = new myclass;
mc->hello();

函数hello是动态分配的,还是非动态分配的?

【问题讨论】:

  • 什么意思?并且不需要那个指针,只需创建一个对象。
  • 我动态分配了那个类,比如int* iptr = new int;。我想知道,这个函数是在计算机内存中的某个地方,还是只是在程序空间中。
  • 动态分配对象时,您只需为特定的实例数据分配空间,函数不是数据,它们是可执行文件中的代码。
  • @AdrianLis 数据也可以在可执行文件中。
  • @LuchianGrigore,如何在可执行数据中动态分配任何内容?

标签: c++ function class memory-management


【解决方案1】:

函数不是对象(至少在 C++ 中),并且没有生命周期。他们就在那里。永远永远。 (同样,从 C++ 的角度来看。)

【讨论】:

  • 在那个示例中,是的。 std::function 或 lambdas 呢?
  • std::function(一旦实例化)是一个类类型的对象,就像 lambdas 一样。它们不是函数,而是函数对象。但是在这两种情况下,类类型都有一个函数operator()(),它是一个函数,没有生命周期,就在那里。
  • 它不仅仅是“就在那里”,它在二进制文件中有一个地址。它是一个代码段,它具有明确定义的存在。由链接器决定(编译器也有责任不进行内联)。
  • @v.oddou 实际上,是的。如果是会员,可能无法直接到此地址;指向成员函数的指针不一定是函数的地址,而是如何获取该地址的方法(例如,从 vtable 中)。 (当然,从 C++ 的角度来看,“永远永远”只涉及 C++ 标准适用的时间跨度。)
【解决方案2】:

函数根本没有“分配”。在引擎盖下,非虚拟函数与类没有固有的物理连接。成员函数只是普通独立函数之上的一层薄薄的语法糖。例如,在您的情况下,成员函数 hello 被转换为普通的独立函数

void myclass_hello(myclass *this) {
  std::cout<<"Hello"<<"\n";
}

当你打电话时

mc->hello();

编译器实际上用

替换了这个调用
myclass_hello(mc);

在 C++ 的早期,当许多 C++ 编译器仅作为 C 编译器的前端实现时,这正是 C++ 成员函数被翻译成 C 函数的方式。

在成员函数和普通独立函数之间的“分配”方面没有区别。无论您创建了多少该类型的对象,都只存在一个成员函数实例。

对于虚函数,事情会变得有点复杂,但这仍然不会产生对成员函数“分配”的任何需求。每个版本的虚成员函数只有一个实例,它仍然独立于实际对象而存在。

【讨论】:

  • 您可以添加虚拟表将类实例“链接”到二进制文件中的已编译函数,方法是将它们的地址存储在类实例本身中。这允许间接函数调用。但是就像你说的,功能虚拟性并不影响它的公民身份。只是包装。
【解决方案3】:

当您深入了解 c++ 的内部结构时,您会发现编译器会对代码进行各种疯狂的操作,例如完全更改函数的名称以支持函数重载。函数不是 C++ 中的对象,而是对函数表的引用。我认为您想知道的是,如果将方法放在类之外会更好,因为该类的每个实例都没有“副本”。事实是,您没有得到函数的“副本”,而是得到了指针变量的副本?答案是否定的,c++ 只会分析代码并将单个函数调用放在您使用的任何地方。在将代码中的变量名称转换为实际内存位置时,将考虑任何“this”或实例数据的引用。

【讨论】:

    【解决方案4】:

    涉及函数时不分配内存。

    这些只是可执行文件中的一堆代码

    【讨论】:

    • 操作系统在启动时必须分配一些空间来保存可执行文件。
    【解决方案5】:

    hello 的实际代码只有一个实例,它在可执行文件中/在程序运行时加载到内存中。类(对象)的所有实例都使用代码的一个实例。

    【讨论】:

      【解决方案6】:

      hello 方法的机器代码是在编译时生成的。由于它不是虚方法,编译器可以决定如何直接调用它。等效代码可能是:

      struct MyStruct {};
      void hello(MyStruct* this)
      {
        std::cout << "Hello" << std::endl;
      }
      int main(int, char**)
      {
        MyStruct* ms = new MyStruct;
        hello(ms);
        return 0;
      }
      

      【讨论】:

        【解决方案7】:

        这完全取决于上下文,更准确地说它是什么类型的函数。 你永远不会分配一个函数,因为它是代码而不是数据,唯一可以动态的是基于每个类调用的函数,这些是虚函数。

        这是一个普通的类成员函数:

        void MyClass::CallFunction()
        {
        }
        

        实际上,编译器和很多 C++ 编译器都会这样做,添加一个通常“不可见”但同时可访问的函数参数,它通常是列表中的第一个,类对象的内存指针,*this。

        void MyClass::CallFunction(MyClass *this)
        {
        }
        

        如果你声明成员函数 static ,你基本上创建了一个在类范围内但不属于类的函数,因此它没有 this 指针。

        由于作用域,编译器会自动引用您的类变量,因此您不必这样做,因此任何属于类对象的内容都可以使用

        this->classVariable = 0;
        

        对于虚函数,编译器创建了一个由编译器处理的 vtable,因此函数覆盖和多态性实际上可以工作。 vtable 仅存储指向函数的指针,因此即使在这种情况下,函数也是固定的。

        由编译器决定在类对象中实际分配哪些部分,这些通常是非常量非静态成员变量,因此您可以将实际对象视为所有变量的简单结构所有的子类和你的主类。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-29
          • 2013-10-31
          • 2021-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-28
          相关资源
          最近更新 更多