我了解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中。 现在我不明白第二个陈述是如何起作用的。根据我的知识,在=之前的部分将创建一个新的Persistent对象,可以通过变量context来引用它。然后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(评论中) 我做了以下实验。
我写了一个Test类,如下所示。 测试 { 上市: 测试(){ cout&lt;&lt; “测试”&lt;&lt; ENDL; } };
在主要功能中我写了测试测试;它输出“Test”,表示在不使用new关键字的情况下创建对象。
答案 0 :(得分: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
可能抛出异常并不重要。 无论我们如何离开foo
,file
都会被正确销毁,因此我们不需要像try
/ finally
那样混乱你会用Java。该类本身就是异常安全,无需用户做任何额外的努力。
尝试在Java中编写一个类似的代码段,保证,即使doStuff
抛出异常,该文件也会立即关闭。它会更长,并且需要用户更多的关注。
答案 1 :(得分: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并将上下文传递给构造函数。您可以使用构造函数初始化程序语法在类中获得等效行为,如我的示例所示。
答案 2 :(得分: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不是指针。
答案 3 :(得分: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);
。