1

我知道Java,但对C++知之甚少。我正在尝试为https://developers.google.com/v8/get_started代码的 main 函数中的前 3 个语句编写一个类。

首先,我对如何在 C++ 中创建对象有疑问。请参阅下面的代码。

HandleScope handle_scope;
Persistent<Context> context = Context::New();
Context::Scope context_scope(context);

我认为在 C++ 中,当您声明一个类的变量时,该类的实例是在该点创建的。您不需要像在 Java 中那样使用 new 关键字。所以第一条语句将创建一个 HandleScope 实例,该实例将存储在 handle_scope 中。现在我不明白第二个语句是如何工作的。据我所知, = 之前的部分将创建一个新的持久对象,该对象可以由变量上下文引用。那么 Context::New() 会创建一个新对象并将其存储在上下文中吗?呵呵,我知道我错了。但我根本不明白它是如何工作的?

我正在尝试为上述内容编写一个 C++ 类。这是我的尝试。

class MyClass {
private:
    HandleScope handle_scope;
    Persistent<Context> context;
    Context::Scope context_scope;

public:
    MyClass(); 
};

MyClass::MyClass()
{
    context = Context::New();
    context_scope = new Context::Scope(context);
}

我是否正确完成了初始化?

编辑:回复 peachykeen(在评论中)我做了以下实验。

我写了一个测试类如下。测试 { public: Test() { cout << "测试" << endl; } };

在主函数中我写了测试测试;它输出“Test”,这意味着在不使用 new 关键字的情况下创建对象。

4

4 回答 4

11

你是对的,在 C++ 中,对象一被定义就被创建。您不需要使用new关键字。

但是,与 Java 不同,对象可以创建具有不同类型的持续时间。使用new在堆上创建一个具有动态存储持续时间的对象:该变量一直存在,直到您明确delete它为止。(并new返回一个指向创建的对象的指针,以便您可以跟踪它)

如果您只是简单地定义一个对象,就像在第一行和第三行中那样,那么它会以自动存储持续时间创建:也就是说,对象会一直存在,直到超出范围。

这意味着您可以在函数内创建对象,并保证在您离开该函数时它们将被销毁——无论您如何离开该函数。无论您是返回还是抛出异常,所有具有自动存储持续时间的对象(未使用创建new)都保证被正确清理。

这意味着您应始终new尽可能避免。如果必须使用new,通常应该将生成的指针包装到智能指针类中,这是一个使用自动存储持续时间创建的对象,以便它自动销毁)。然后智能指针将delete自动调用新分配的对象,再次确保您不会泄漏内存。

这种区别是一个非常强大的工具,优秀的 C++ 程序员需要很好地理解它。它是避免内存泄漏的关键,或者更一般地说,是避免各种资源泄漏,并且在某些方面,它比 Java 的垃圾收集器更强大。

例如,假设我们希望打开一个文件,然后向其中写入一些数据。在 C++ 中,我们可以这样做:

void foo() {
    std::ofstream file("foo.txt");
    doStuff(file); // call a function which does something with the file   
}

并且因为file是在没有使用的情况下声明的new,因为它具有自动存储持续时间,所以我们保证当它超出范围时会调用它的析构函数,并且它会被正确清理——也就是说,流将被刷新,并且文件句柄将被关闭。

doStuff是否可能引发异常并不重要。无论我们如何离开foofile都会被正确销毁,所以我们不需要像在 Java 中那样搞乱try/ 。finally该类本身是异常安全的,不需要用户进行任何额外的工作。

尝试用 Java 编写一个类似的代码片段,它保证即使doStuff抛出异常,文件也会立即关闭。它会更长,并且需要用户更加小心。

于 2012-07-29T17:50:38.120 回答
0
Persistent<Context> context = Context::New();

Persistent<Context>如果 c-tor 不明确,则创建类型的对象,从 Context::New 返回的初始化。

简单的例子。

#include <iostream>

class C
{
public:
    C(int)
    {
        std::cout << "C::C(int)" << std::endl;
    }
};

int main()
{
    C c = 1;
}

你的课应该是

class MyClass {
private:
    HandleScope handle_scope;
    Persistent<Context> context;
    Context::Scope context_scope;

public:
    MyClass(); 
};

MyClass::MyClass():context(Context::New()),
    context_scope(Context::Scope(context))
{
}

如果 Context::Scope 不是指针。

于 2012-07-29T17:53:14.483 回答
0

这将是等效的类:

class MyClass {
private:
    HandleScope handle_scope;
    Persistent<Context> context;
    Context::Scope context_scope;

public:
    MyClass(); 
};

MyClass::MyClass()
: context(Context::New()),
  context_scope(context)
{
}

当您编写这样的语句时:

Persistent<Context> context = Context::New();

您正在使用复制构造函数构造上下文。这与创建对象然后分配新值不同,尽管结果可能通常是等效的。

同样这个声明:

Context::Scope context_scope(context);

正在构造 context_scope 并将上下文传递给构造函数。您可以使用构造函数初始化程序语法在类中获得等效的行为,如我的示例中所示。

于 2012-07-29T17:50:13.013 回答
0

要创建对象的实例,您只需要:Type name; 关键字new创建指向对象的指针。通常,为了初始化对象,我们使用括号:Type name(parameter);有时,当对象支持复制时,您可以使用返回对象并将其分配给该对象的函数:Type name = Some_function_that_returns_Type();您现在可以name像使用任何其他对象一样使用。如果你说Type name = new Type;,你会得到一个编译器错误。关键字 new 返回一个指针。说得对Type * name = new Type;。(注意*,表示它是一个指向类的指针,Type名为name。当我引用它时,Type它是任何对象,例如您的 HandleScope。当我引用name,它是您正在创建的新对象。最重要的是:new是一个完全不同的关键字,指的是指针。如果您不使用指针,请不要使用它。使用基本格式Type name(parameter, another_param);

于 2012-07-29T18:14:52.030 回答