代码之家  ›  专栏  ›  技术社区  ›  Michael Stum

对象已在声明中初始化?

c++
  •  11
  • Michael Stum  · 技术社区  · 15 年前

    我正在尝试理解C++中的一些东西。基本上我有这个:

    class SomeClass {
        public:
            SomeClass();
        private:
            int x;
    };
    
    SomeClass::SomeClass(){
        x = 10;
    }
    
    int main() {
        SomeClass sc;
        return 0;
    }
    

    我原以为sc是SomeClass类型的未初始化变量,但从各种教程中我发现这个声明实际上是一个调用SomeClass()构造函数的初始化,而不需要调用“sc=new SomeClass();”或者类似的。

    当我来自C世界(并且知道一点C,但没有C++)时,我试图理解什么时候需要新的东西,什么时候释放像这样的对象。我发现了一个叫拉尔的模式,似乎是不相关的。

    这种类型的初始化调用了什么?我如何知道某个东西是纯粹的声明还是完全初始化?

    5 回复  |  直到 15 年前
        1
  •  21
  •   Matthieu M.    15 年前

    • 自动变量和动态分配变量的区别
    • 雷伊
    • C#平行

    int main(int argc, char* argv[])  // 1
    {                                 // 2
      SomeClass sc;                   // 3
      sc.foo();                       // 4
      return 0;                       // 5
    }                                 // 6
    

    在这里 sc 是自动变量。在第(3)行执行成功后,保证完全初始化(即保证构造函数已运行)。它的析构函数将在第(6)行自动调用。

    我们一般讲变量的作用域:从声明点到相应的右括号;并且该语言保证在退出作用域时销毁,无论是使用 return

    另一方面,C++还具有动态变量,即使用 new

    int main(int argc, char* argv[])  // 1
    {                                 // 2
      SomeClass* sc = 0;              // 3
      sc = new SomeClass();           // 4
      sc->foo();                      // 5
      return 0;                       // 6
    }                                 // 7 (!! leak)
    

    在这里 仍然是一个自动变量,但是它的类型不同:它现在是指向类型为的变量的指针 SomeClass .

    南卡罗来纳州 分配了空指针值( nullptr 某类 . 请注意,该语言本身并不保证任何初始化,因此您需要显式地分配一些内容,否则您将有一个垃圾值。

    在第(4)行中,我们构建了一个动态变量(使用 新的 运算符)并将其地址分配给 南卡罗来纳州 . 注意,动态变量本身是未命名的,系统只给我们一个指向它的指针(地址)。

    南卡罗来纳州

    the first

    • 一个对象在其构造函数运行到完成时就存在。这意味着如果构造函数抛出,对象就永远不会存在(将其视为怀孕的意外)。

    如果我们回到第一个例子:

    int main(int argc,char*argv[])//1
    SomeClass sc;//三
    sc.foo();                       // 4
    }                                 // 6
    

    从第(4)行到第(5)行(含)都是活动的。在第(3)行中,它正在被构造(可能由于各种原因而失败),在第(6)行中,它正在被破坏。

    雷伊

    RAII的意思是

    在C++中,由于我们没有垃圾收集,这个习惯用法主要应用于内存管理,但它也适用于任何其他类型的资源:多线程环境中的锁、文件锁、网络中的套接字/连接等。

    int main(int argc, char* argv[])
    {
      std::unique_ptr<SomeClass> sc = new SomeClass();
      sc->foo();
      return 0;
    }
    

    它与第一个示例非常相似,只是我动态地分配了 某类 . 然后将此实例的地址交给 对象,类型 std::unique_ptr<SomeClass> (它是C++ 0x设备,使用 boost::scoped_ptr unique_ptr 南卡罗来纳州 被摧毁了。

    std::shared_ptr 标准::共享\u ptr 不是灵丹妙药。

    • 尽量使用自动变量
    • 对于动态变量,不要调用 delete 你自己,总是利用RAII设施

    我个人认为 删除

    C#平行

    在C语言中,主要使用动态变量 *

    • 如果您只是声明一个变量,而没有赋值,那么它的值是空的:本质上,您只是在操作指针,因此您有一个空指针(感谢上帝,初始化是有保证的)
    • 新的 要创建值,这将调用对象的构造函数并生成对象的地址;注意,动态变量的语法与C++类似。

    using IDisposable 内存接口。

    :如果在声明变量后其值为 null ,则它将是一个动态变量。我相信这是为了 int 值将为0表示不是,但我已经3年没有为课程项目使用C了,所以。。。

        2
  •  3
  •   Stefano Borini    15 年前

    main()的第一行是在堆栈上分配一个SomeClass对象。这个 new 运算符在堆上分配对象,返回 指针 类实例。这最终导致通过 . (与实例)或 -> (用指针)

    因为您知道C,所以每次您说 int i;

    int *i;
    i = (int *)malloc(sizeof(int));
    *i=5;
    

    虽然堆栈上分配的内容的释放是自动完成的,但堆上分配的内容的释放必须由程序员完成。

    您的困惑源于C#(我不使用它,但我知道它类似于Java)没有堆栈分配这一事实。你说什么的时候做什么 SomeClass sc SomeClass 当前未初始化的引用,直到 新的 新的 ,您没有对象。在C++中,情况并非如此。C++中没有引用的概念,类似于C++(或java),尽管C++中只有在函数调用期间才有引用(实际上是通过引用范式)。默认情况下,C++通过值传递,这意味着在函数调用中复制对象。然而,这并不是全部。查看评论以获得更准确的详细信息。

        3
  •  2
  •   TreDubZedd    15 年前

    就你而言, sc 在堆栈上分配,使用 SomeClass . 因为实例在堆栈上,所以从函数返回时它将被销毁(如果您实例化 SomeClass sc 在从调用的函数中 main --分配给的内存 南卡罗来纳州 将在返回到 主要的

    这个 new 关键字,而不是在运行时堆栈上分配内存,而是在堆上分配内存。因为C++没有自动垃圾收集,所以程序员(程序员)负责分配堆上分配的任何内存(使用 delete

        4
  •  2
  •   CB Bailey    15 年前

    当您声明一个变量时(没有 extern )在功能范围内(例如 main 主要的

    当一个对象存在时,如果它有一个用户声明的构造函数,那么它的一个构造函数被用来初始化它。类似地,如果它有一个用户声明的析构函数,则在对象超出范围执行任何必需的清理操作时使用它 . 这与具有终结器的语言不同,终结器可以运行,也可以不运行,当然不在确定的时间点。更像是 using / IDisposable .

    new

    使用创建对象时 新的 delete 表情。为了确保程序员不会忘记这样做,通常使用某种智能指针对象来自动管理它,例如 shared_ptr

        5
  •  2
  •   Greg Rogers    15 年前

    其他一些答案基本上告诉您“sc在堆栈上分配,new在堆上分配对象”。我不喜欢这样想,因为它将实现细节(堆栈/堆)与代码的语义相结合。既然你已经习惯了C的做事方式,我想这也会产生歧义。相反,我更喜欢的方式是C++标准描述它的方式:

    sc是SomeClass类型的变量,在块范围内声明(即,组成main函数的大括号)。这被称为 . 因为没有申报 static extern 自动存储时间 . 这意味着 SomeClass sc; 执行时,变量将被初始化(通过运行其构造函数),当变量退出块而超出范围时,它将被销毁(通过运行其析构函数-因为您没有析构函数,并且您的对象是纯旧数据,所以不会执行任何操作)。

    早些时候我说“因为它没有申报 静止的 外部 “,如果你这样声明的话 静态存储时间 . 它将在程序启动前初始化(从技术上讲,在块范围内,它将在第一次使用时初始化),并在程序终止后销毁。

    使用时 new . 调用时将初始化此对象 新的 delete std::vector ),它管理包含值的生存期。容器变量本身可以进入静态存储或自动存储。