先看一段代码:
void Isolate::TearDown() {
TRACE_ISOLATE(tear_down);
tracing_cpu_profiler_.reset();
if (FLAG_stress_sampling_allocation_profiler > 0) {
heap_profiler()->StopSamplingHeapProfiler();
}
// Temporarily set this isolate as current so that various parts of
// the isolate can access it in their destructors without having a
// direct pointer. We don't use Enter/Exit here to avoid
// initializing the thread data.
PerIsolateThreadData* saved_data = CurrentPerIsolateThreadData();
DCHECK_EQ(base::Relaxed_Load(&isolate_key_created_), 1);
Isolate* saved_isolate =
reinterpret_cast<Isolate*>(base::Thread::GetThreadLocal(isolate_key_));
SetIsolateThreadLocals(this, nullptr);
Deinit();
{
base::LockGuard<base::Mutex> lock_guard(&thread_data_table_mutex_);
thread_data_table_.RemoveAllThreads();
}
#ifdef DEBUG
non_disposed_isolates_--;
#endif // DEBUG
delete this;//!!!此处似乎有危险
// Restore the previous current isolate.
SetIsolateThreadLocals(saved_isolate, saved_data);
}
上面看到这个Isolate类的成员函数里面竟然调用了delete this的语句,而且后面还有代码需要执行,初看到这个语句心里一惊,尼玛这要出大事情。搜了一下这个工程好多地方有这种写法,看来是故意为之且没问题。有段时间没用c++了复习下,安全使用此语句需要满足以下条件:
1.确保对象是new出来的;
2.确保delete完后不会用该对象调用其它(非静态)成员函数;
3.确保delete完后不能访问对象的任何部分;
4.确保delete完后this指针不会被访问。
再回到上面那段代码分析:
delete下面一行调用了SetIsolateThreadLocals
void Isolate::SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data) {
base::Thread::SetThreadLocal(isolate_key_, isolate);
base::Thread::SetThreadLocal(per_isolate_thread_data_key_, data);
}
传入的两个参数实际为TearDown函数内部两个局部变量,满足条件2、3、4。
再看TearDown函数调用后情况
void Isolate::Dispose() {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
if (!Utils::ApiCheck(!isolate->IsInUse(),
"v8::Isolate::Dispose()",
"Disposing the isolate that is entered by a thread.")) {
return;
}
isolate->TearDown();
}
TearDown在Dispose函数末尾调用,满足条件;
最后看看Dispose函数调用情况:
SnapshotCreator::~SnapshotCreator() {
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(data->created_);
Isolate* isolate = data->isolate_;
isolate->Exit();
isolate->Dispose();//此处调用
delete data;
}
void Shell::OnExit(v8::Isolate* isolate) {
// Dump basic block profiling data.
if (i::FLAG_turbo_profiling) {
i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get();
i::StdoutStream{} << *profiler;
}
isolate->Dispose();
//此处后面还有代码,但是已经没有isolate的引用
}
从上面看出Dispose函数调用后,基本就不用对象了。
所以delete this;一般在析构函数或释放对象函数里使用,比如引用计数方式里的使用:
inline void Unref() { if (--refs == 0) delete this; }
从开发角度讲,我们一般调用第三方封装的类似函数接口即可,尽量不直接这样写,除非源码级别。
网友评论