C++ delete this

2019-12-31  本文已影响0人  胖子罗

先看一段代码:

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; }

从开发角度讲,我们一般调用第三方封装的类似函数接口即可,尽量不直接这样写,除非源码级别。

上一篇 下一篇

猜你喜欢

热点阅读