Chromium中的C++11新特性

528 阅读6分钟

Chromium中的C++11新特性

auto

// src\cc\trees\layer_tree_host_impl.cc
bool LayerTreeHostImpl::IsCurrentlyScrollingViewport() const {
  auto* node = CurrentlyScrollingNode();
  if (!node)
    return false;
  if (!viewport()->MainScrollLayer())
    return false;
  return node->id == viewport()->MainScrollLayer()->scroll_tree_index();
}

// src\cc\trees\layer_tree_host_impl_unittest.cc
static void ExpectClearedScrollDeltasRecursive(LayerImpl* root) {
  for (auto* layer : *root->layer_tree_impl())
    ASSERT_EQ(ScrollDelta(layer), gfx::Vector2d());
}

decltype

// src\base\bind_internal.h
template <typename T>
decltype(auto) Unwrap(T&& o) {
  return Unwrapper<T>::Unwrap(std::forward<T>(o));
}

trailing return type

// src\base\trace_event\memory_usage_estimator.h
template <class T>
auto EstimateMemoryUsage(const T& object)
    -> decltype(object.EstimateMemoryUsage());

default

// src\base\callback.h
template <typename R, typename... Args>
class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
 public:
  using RunType = R(Args...);
  using PolymorphicInvoke = R (*)(internal::BindStateBase*,
                                  internal::PassingTraitsType<Args>...);

  constexpr RepeatingCallback() = default;

  explicit RepeatingCallback(internal::BindStateBase* bind_state)
      : internal::CallbackBaseCopyable(bind_state) {}

  // Copyable and movable.
  RepeatingCallback(const RepeatingCallback&) = default;
  RepeatingCallback& operator=(const RepeatingCallback&) = default;
  RepeatingCallback(RepeatingCallback&&) noexcept = default;
  RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default;

  bool Equals(const RepeatingCallback& other) const {
    return EqualsInternal(other);
  }

  R Run(Args... args) const & {
    PolymorphicInvoke f =
        reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke());
    return f(this->bind_state_.get(), std::forward<Args>(args)...);
  }

  R Run(Args... args) && {
    // Move the callback instance into a local variable before the invocation,
    // that ensures the internal state is cleared after the invocation.
    // It's not safe to touch |this| after the invocation, since running the
    // bound function may destroy |this|.
    RepeatingCallback cb = std::move(*this);
    PolymorphicInvoke f =
        reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
    return f(cb.bind_state_.get(), std::forward<Args>(args)...);
  }
};

delete

// src\base\callback.h
template <typename R, typename... Args>
class OnceCallback<R(Args...)> : public internal::CallbackBase {
 public:
  using RunType = R(Args...);
  using PolymorphicInvoke = R (*)(internal::BindStateBase*,
                                  internal::PassingTraitsType<Args>...);

  constexpr OnceCallback() = default;

  explicit OnceCallback(internal::BindStateBase* bind_state)
      : internal::CallbackBase(bind_state) {}

  OnceCallback(const OnceCallback&) = delete;
  OnceCallback& operator=(const OnceCallback&) = delete;

  OnceCallback(OnceCallback&&) noexcept = default;
  OnceCallback& operator=(OnceCallback&&) noexcept = default;

  OnceCallback(RepeatingCallback<RunType> other)
      : internal::CallbackBase(std::move(other)) {}

  OnceCallback& operator=(RepeatingCallback<RunType> other) {
    static_cast<internal::CallbackBase&>(*this) = std::move(other);
    return *this;
  }

  bool Equals(const OnceCallback& other) const { return EqualsInternal(other); }

  R Run(Args... args) const & {
    static_assert(!sizeof(*this),
                  "OnceCallback::Run() may only be invoked on a non-const "
                  "rvalue, i.e. std::move(callback).Run().");
    NOTREACHED();
  }

  R Run(Args... args) && {
    // Move the callback instance into a local variable before the invocation,
    // that ensures the internal state is cleared after the invocation.
    // It's not safe to touch |this| after the invocation, since running the
    // bound function may destroy |this|.
    OnceCallback cb = std::move(*this);
    PolymorphicInvoke f =
        reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
    return f(cb.bind_state_.get(), std::forward<Args>(args)...);
  }
};

// src\base\macros.h
// Put this in the declarations for a class to be uncopyable.
#define DISALLOW_COPY(TypeName) \
  TypeName(const TypeName&) = delete

// Put this in the declarations for a class to be unassignable.
#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete

// Put this in the declarations for a class to be uncopyable and unassignable.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  DISALLOW_COPY(TypeName);                 \
  DISALLOW_ASSIGN(TypeName)

final

// src\base\cpu.h
class BASE_EXPORT CPU final {
 public:
  CPU();

  enum IntelMicroArchitecture {
    PENTIUM,
    SSE,
    SSE2,
    SSE3,
    SSSE3,
    SSE41,
    SSE42,
    AVX,
    AVX2,
    MAX_INTEL_MICRO_ARCHITECTURE
  };

  // Accessors for CPU information.
  const std::string& vendor_name() const { return cpu_vendor_; }
  int signature() const { return signature_; }
  int stepping() const { return stepping_; }
  int model() const { return model_; }
  int family() const { return family_; }
  int type() const { return type_; }
  int extended_model() const { return ext_model_; }
  int extended_family() const { return ext_family_; }
  bool has_mmx() const { return has_mmx_; }
  bool has_sse() const { return has_sse_; }
  bool has_sse2() const { return has_sse2_; }
  bool has_sse3() const { return has_sse3_; }
  bool has_ssse3() const { return has_ssse3_; }
  bool has_sse41() const { return has_sse41_; }
  bool has_sse42() const { return has_sse42_; }
  bool has_popcnt() const { return has_popcnt_; }
  bool has_avx() const { return has_avx_; }
  bool has_avx2() const { return has_avx2_; }
  bool has_aesni() const { return has_aesni_; }
  bool has_non_stop_time_stamp_counter() const {
    return has_non_stop_time_stamp_counter_;
  }

  IntelMicroArchitecture GetIntelMicroArchitecture() const;
  const std::string& cpu_brand() const { return cpu_brand_; }

 private:
  // Query the processor for CPUID information.
  void Initialize();

  int signature_;  // raw form of type, family, model, and stepping
  int type_;  // process type
  int family_;  // family of the processor
  int model_;  // model of processor
  int stepping_;  // processor revision number
  int ext_model_;
  int ext_family_;
  bool has_mmx_;
  bool has_sse_;
  bool has_sse2_;
  bool has_sse3_;
  bool has_ssse3_;
  bool has_sse41_;
  bool has_sse42_;
  bool has_popcnt_;
  bool has_avx_;
  bool has_avx2_;
  bool has_aesni_;
  bool has_non_stop_time_stamp_counter_;
  std::string cpu_vendor_;
  std::string cpu_brand_;
};

override

// src\base\files\file_util_unittest.cc
class FileUtilTest : public PlatformTest {
 protected:
  void SetUp() override {
    PlatformTest::SetUp();
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  }

  ScopedTempDir temp_dir_;
};

rvalue references

// src\base\containers\flat_map.h
template <class Key, class Mapped, class Compare = std::less<>>
class flat_map : public ::base::internal::flat_tree<
                     Key,
                     std::pair<Key, Mapped>,
                     ::base::internal::GetKeyFromValuePairFirst<Key, Mapped>,
                     Compare> {
 private:
  using tree = typename ::base::internal::flat_tree<
      Key,
      std::pair<Key, Mapped>,
      ::base::internal::GetKeyFromValuePairFirst<Key, Mapped>,
      Compare>;

 public:
  using key_type = typename tree::key_type;
  using mapped_type = Mapped;
  using value_type = typename tree::value_type;
  using iterator = typename tree::iterator;
  using const_iterator = typename tree::const_iterator;

  // --------------------------------------------------------------------------
  // Lifetime and assignments.
  //
  // Note: we could do away with these constructors, destructor and assignment
  // operator overloads by inheriting |tree|'s, but this breaks the GCC build
  // due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84782 (see
  // https://crbug.com/837221).

  flat_map() = default;
  explicit flat_map(const Compare& comp);

  template <class InputIterator>
  flat_map(InputIterator first,
           InputIterator last,
           FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
           const Compare& comp = Compare());

  flat_map(const flat_map&) = default;
  flat_map(flat_map&&) noexcept = default;

  flat_map(std::vector<value_type> items,
           FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
           const Compare& comp = Compare());

  flat_map(std::initializer_list<value_type> ilist,
           FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
           const Compare& comp = Compare());

  ~flat_map() = default;

  flat_map& operator=(const flat_map&) = default;
  flat_map& operator=(flat_map&&) = default;
  // Takes the first if there are duplicates in the initializer list.
  flat_map& operator=(std::initializer_list<value_type> ilist);

  // --------------------------------------------------------------------------
  // Map-specific insert operations.
  //
  // Normal insert() functions are inherited from flat_tree.
  //
  // Assume that every operation invalidates iterators and references.
  // Insertion of one element can take O(size).

  mapped_type& operator[](const key_type& key);
  mapped_type& operator[](key_type&& key);

  template <class K, class M>
  std::pair<iterator, bool> insert_or_assign(K&& key, M&& obj);
  template <class K, class M>
  iterator insert_or_assign(const_iterator hint, K&& key, M&& obj);

  template <class K, class... Args>
  std::enable_if_t<std::is_constructible<key_type, K&&>::value,
                   std::pair<iterator, bool>>
  try_emplace(K&& key, Args&&... args);

  template <class K, class... Args>
  std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator>
  try_emplace(const_iterator hint, K&& key, Args&&... args);

  // --------------------------------------------------------------------------
  // General operations.
  //
  // Assume that swap invalidates iterators and references.

  void swap(flat_map& other) noexcept;

  friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); }
};

move constructors and move assignment operators

// src\base\containers\circular_deque.h
circular_deque(circular_deque&& other) noexcept
    : buffer_(std::move(other.buffer_)),
      begin_(other.begin_),
      end_(other.end_) {
  other.begin_ = 0;
  other.end_ = 0;
}

circular_deque& operator=(circular_deque&& other) noexcept {
  if (&other == this)
    return *this;
  // We're about to overwrite the buffer, so don't free it in clear to
  // avoid doing it twice.
  ClearRetainCapacity();
  buffer_ = std::move(other.buffer_);
  begin_ = other.begin_;
  end_ = other.end_;
  other.begin_ = 0;
  other.end_ = 0;
  IncrementGeneration();
  return *this;
}

scoped enums

// src\base\mac\mach_port_util.h
enum class MachCreateError {
    ERROR_MAKE_RECEIVE_PORT,
    ERROR_SET_ATTRIBUTES,
    ERROR_EXTRACT_DEST_RIGHT,
    ERROR_SEND_MACH_PORT,
};

constexpr

// src\base\callback_internal.h
class BASE_EXPORT CallbackBaseCopyable : public CallbackBase {
 public:
  CallbackBaseCopyable(const CallbackBaseCopyable& c);
  CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept;
  CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c);
  CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept;

 protected:
  constexpr CallbackBaseCopyable() = default;
  explicit CallbackBaseCopyable(BindStateBase* bind_state)
      : CallbackBase(bind_state) {}
  ~CallbackBaseCopyable() = default;
};

list initialization

// src\base\trace_event\trace_event_unittest.cc
DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name,
                                                      const char* phase) {
  JsonKeyValue key_values[] = {{"name", name, IS_EQUAL},
                               {"ph", phase, IS_EQUAL},
                               {nullptr, nullptr, IS_EQUAL}};
  return FindMatchingTraceEntry(key_values);
}

delegating constructors

inherited constructors

// src\third_party\abseil-cpp\absl\types\internal\variant.h
template <class... T>
class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> {
 private:
  using Base = VariantStateBase<T...>;

 protected:
  using Base::Base;

  VariantStateBaseDestructorNontrivial() = default;
  VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) =
      default;
  VariantStateBaseDestructorNontrivial(
      const VariantStateBaseDestructorNontrivial&) = default;
  VariantStateBaseDestructorNontrivial& operator=(
      VariantStateBaseDestructorNontrivial&&) = default;
  VariantStateBaseDestructorNontrivial& operator=(
      const VariantStateBaseDestructorNontrivial&) = default;

  struct Destroyer {
    template <std::size_t I>
    void operator()(SizeT<I> i) const {
      using Alternative =
          typename absl::variant_alternative<I, variant<T...>>::type;
      variant_internal::AccessUnion(self->state_, i).~Alternative();
    }

    void operator()(SizeT<absl::variant_npos> /*i*/) const {
      // This space intentionally left blank
    }

    VariantStateBaseDestructorNontrivial* self;
  };

  void destroy() {
    variant_internal::visit_indices<sizeof...(T)>(Destroyer{this}, index_);
  }

  ~VariantStateBaseDestructorNontrivial() { destroy(); }

 protected:
  using Base::index_;
  using Base::state_;
};

nullptr

// src\base\callback_list.h
template <typename Sig> class CallbackList;

template <typename... Args>
class CallbackList<void(Args...)>
    : public internal::CallbackListBase<RepeatingCallback<void(Args...)>> {
 public:
  using CallbackType = RepeatingCallback<void(Args...)>;

  CallbackList() = default;

  template <typename... RunArgs>
  void Notify(RunArgs&&... args) {
    auto it = this->GetIterator();
    CallbackType* cb;
    while ((cb = it.GetNext()) != nullptr) {
      cb->Run(args...);
    }
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(CallbackList);
};

type aliases

// src\base\callback_forward.h
namespace base {

template <typename Signature>
class OnceCallback;

template <typename Signature>
class RepeatingCallback;

template <typename Signature>
using Callback = RepeatingCallback<Signature>;

// Syntactic sugar to make Callback<void()> easier to declare since it
// will be used in a lot of APIs with delayed execution.
using OnceClosure = OnceCallback<void()>;
using RepeatingClosure = RepeatingCallback<void()>;
using Closure = Callback<void()>;

}  // namespace base

variadic templates

// src\base\callback_helpers.h
template <typename... Args>
class AdaptCallbackForRepeatingHelper final {
 public:
  explicit AdaptCallbackForRepeatingHelper(OnceCallback<void(Args...)> callback)
      : callback_(std::move(callback)) {
    DCHECK(callback_);
  }

  void Run(Args... args) {
    if (subtle::NoBarrier_AtomicExchange(&has_run_, 1))
      return;
    DCHECK(callback_);
    std::move(callback_).Run(std::forward<Args>(args)...);
  }

 private:
  volatile subtle::Atomic32 has_run_ = 0;
  base::OnceCallback<void(Args...)> callback_;

  DISALLOW_COPY_AND_ASSIGN(AdaptCallbackForRepeatingHelper);
};

lambda expressions

// src\base\time\time.cc
TimeTicks TimeTicks::UnixEpoch() {
  static const base::NoDestructor<base::TimeTicks> epoch([]() {
    return subtle::TimeTicksNowIgnoringOverride() -
           (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch());
  }());
  return *epoch;
}

noexcept specifier and noexcept operator

// src\base\optional.h
constexpr Optional(Optional&& other) noexcept(
    std::is_nothrow_move_constructible<T>::value) = default;

// src\base\callback_internal.cc
CallbackBaseCopyable::CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept =
    default;

// src\base\optional_unittest.cc
static_assert(
    noexcept(Optional<int>(std::declval<Optional<int>>())),
    "move constructor for noexcept move-constructible T must be noexcept "
    "(trivial copy, trivial move)");

alignof and alignas

// src\base\containers\stack_container_unittest.cc
namespace {

template <size_t alignment>
class AlignedData {
 public:
  AlignedData() { memset(data_, 0, alignment); }
  ~AlignedData() = default;
  alignas(alignment) char data_[alignment];
};

}  // anonymous namespace

StackVector<wchar_t, 16> text;
text->push_back(L'A');
EXPECT_ALIGNED(&text[0], alignof(wchar_t));

std::unique_ptr

// src\base\trace_event\trace_event_unittest.cc
void TraceEventTestFixture::OnTraceDataCollected(
    WaitableEvent* flush_complete_event,
    const scoped_refptr<base::RefCountedString>& events_str,
    bool has_more_events) {
  num_flush_callbacks_++;
  if (num_flush_callbacks_ > 1) {
    EXPECT_FALSE(events_str->data().empty());
  }
  AutoLock lock(lock_);
  json_output_.json_output.clear();
  trace_buffer_.Start();
  trace_buffer_.AddFragment(events_str->data());
  trace_buffer_.Finish();

  std::unique_ptr<Value> root =
      base::JSONReader::Read(json_output_.json_output, JSON_PARSE_RFC);

  if (!root.get()) {
    LOG(ERROR) << json_output_.json_output;
  }

  ListValue* root_list = nullptr;
  ASSERT_TRUE(root.get());
  ASSERT_TRUE(root->GetAsList(&root_list));

  // Move items into our aggregate collection
  while (root_list->GetSize()) {
    std::unique_ptr<Value> item;
    root_list->Remove(0, &item);
    trace_parsed_.Append(std::move(item));
  }

  if (!has_more_events)
    flush_complete_event->Signal();
}

range-for (based on a Boost library)

// src\base\i18n\rtl.cc
void EnsureTerminatedDirectionalFormatting(string16* text) {
  int count = 0;
  for (auto c : *text) {
    if (c == kLeftToRightEmbeddingMark || c == kRightToLeftEmbeddingMark ||
        c == kLeftToRightOverride || c == kRightToLeftOverride) {
      ++count;
    } else if (c == kPopDirectionalFormatting && count > 0) {
      --count;
    }
  }
  for (int j = 0; j < count; j++)
    text->push_back(kPopDirectionalFormatting);
}

static_assert (based on a Boost library)

// src\base\allocator\malloc_zone_functions_mac.cc
static_assert(std::is_pod<MallocZoneFunctions>::value,
              "MallocZoneFunctions must be POD");

explicit

// src\base\sequenced_task_runner.h
struct BASE_EXPORT OnTaskRunnerDeleter {
  explicit OnTaskRunnerDeleter(scoped_refptr<SequencedTaskRunner> task_runner);
  ~OnTaskRunnerDeleter();

  OnTaskRunnerDeleter(OnTaskRunnerDeleter&&);
  OnTaskRunnerDeleter& operator=(OnTaskRunnerDeleter&&);

  // For compatibility with std:: deleters.
  template <typename T>
  void operator()(const T* ptr) {
    if (ptr)
      task_runner_->DeleteSoon(FROM_HERE, ptr);
  }

  scoped_refptr<SequencedTaskRunner> task_runner_;
};

std::atomic

// src\base\allocator\partition_allocator\spin_lock.h
class BASE_EXPORT SpinLock {
 public:
  constexpr SpinLock() = default;
  ~SpinLock() = default;
  using Guard = std::lock_guard<SpinLock>;

  ALWAYS_INLINE void lock() {
    static_assert(sizeof(lock_) == sizeof(int),
                  "int and lock_ are different sizes");
    if (LIKELY(!lock_.exchange(true, std::memory_order_acquire)))
      return;
    LockSlow();
  }

  ALWAYS_INLINE void unlock() { lock_.store(false, std::memory_order_release); }

 private:
  // This is called if the initial attempt to acquire the lock fails. It's
  // slower, but has a much better scheduling and power consumption behavior.
  void LockSlow();

  std::atomic_int lock_{0};
};

std::call_once

// src\third_party\leveldatabase\src\port\port_stdcxx.h
inline void InitOnce(OnceType* once, void (*initializer)()) {
  std::call_once(*once, *initializer);
}

std::condition_variable

// src\base\synchronization\condition_variable.h
class BASE_EXPORT ConditionVariable {
 public:
  // Construct a cv for use with ONLY one user lock.
  explicit ConditionVariable(Lock* user_lock);

  ~ConditionVariable();

  // Wait() releases the caller's critical section atomically as it starts to
  // sleep, and the reacquires it when it is signaled. The wait functions are
  // susceptible to spurious wakeups. (See usage note 1 for more details.)
  void Wait();
  void TimedWait(const TimeDelta& max_time);

  // Broadcast() revives all waiting threads. (See usage note 2 for more
  // details.)
  void Broadcast();
  // Signal() revives one waiting thread.
  void Signal();

 private:

#if defined(OS_WIN)
/*  xp_2345: lock
  CHROME_CONDITION_VARIABLE cv_;
  CHROME_SRWLOCK* const srwlock_;
*/
  std::unique_ptr<xp_2345::ConditionVarImpl> impl_;

#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
  pthread_cond_t condition_;
  pthread_mutex_t* user_mutex_;
#endif

#if DCHECK_IS_ON()
  //base::Lock* const user_lock_;  // Needed to adjust shadow lock state on wait.
#endif

  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
};

参考文献

  1. en.cppreference.com/w/cpp/11
  2. c.biancheng.net/cplus/11/
  3. mp.weixin.qq.com/s?__biz=Mzk…
  4. blog.csdn.net/y1196645376…
  5. developer.51cto.com/art/202007/…
  6. blog.csdn.net/weixin_3833…
  7. www.jianshu.com/p/ef66ba669…
  8. www.jianshu.com/p/f964b929f…
  9. mp.weixin.qq.com/s?__biz=Mzk…
  10. www.cnblogs.com/xinxue/p/54…
  11. www.cnblogs.com/qicosmos/p/…
  12. blog.csdn.net/K346K346/ar…
  13. www.cnblogs.com/Braveliu/p/…
  14. mp.weixin.qq.com/s?__biz=Mzk…
  15. mp.weixin.qq.com/s?__biz=Mzk…