Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: base/memory/ref_counted.h

Issue 2471043002: Allow icomplete types in scoped_refptr<T>. (Closed)
Patch Set: Release can delete this Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/test/opaque_ref_counted.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_MEMORY_REF_COUNTED_H_ 5 #ifndef BASE_MEMORY_REF_COUNTED_H_
6 #define BASE_MEMORY_REF_COUNTED_H_ 6 #define BASE_MEMORY_REF_COUNTED_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <cassert> 10 #include <cassert>
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 // // now, |a| and |b| each own a reference to the same MyFoo object. 264 // // now, |a| and |b| each own a reference to the same MyFoo object.
265 // } 265 // }
266 // 266 //
267 template <class T> 267 template <class T>
268 class scoped_refptr { 268 class scoped_refptr {
269 public: 269 public:
270 typedef T element_type; 270 typedef T element_type;
271 271
272 scoped_refptr() {} 272 scoped_refptr() {}
273 273
274 scoped_refptr(T* p) : ptr_(p) { 274 scoped_refptr(T* p) : ptr_(p), ptr_caller_(&PtrCallerImpl) {
275 if (ptr_) 275 if (ptr_)
276 AddRef(ptr_); 276 ptr_caller_(ptr_, PtrCall::AddRef);
277 } 277 }
278 278
279 // Copy constructor. 279 // Copy constructor.
280 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { 280 scoped_refptr(const scoped_refptr<T>& r)
281 : ptr_(r.ptr_), ptr_caller_(r.ptr_caller_) {
281 if (ptr_) 282 if (ptr_)
282 AddRef(ptr_); 283 ptr_caller_(ptr_, PtrCall::AddRef);
283 } 284 }
284 285
285 // Copy conversion constructor. 286 // Copy conversion constructor.
286 template <typename U, 287 template <typename U,
287 typename = typename std::enable_if< 288 typename = typename std::enable_if<
288 std::is_convertible<U*, T*>::value>::type> 289 std::is_convertible<U*, T*>::value>::type>
289 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { 290 scoped_refptr(const scoped_refptr<U>& r)
291 : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) {
290 if (ptr_) 292 if (ptr_)
291 AddRef(ptr_); 293 ptr_caller_(ptr_, PtrCall::AddRef);
292 } 294 }
293 295
294 // Move constructor. This is required in addition to the conversion 296 // Move constructor. This is required in addition to the conversion
295 // constructor below in order for clang to warn about pessimizing moves. 297 // constructor below in order for clang to warn about pessimizing moves.
296 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } 298 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()), ptr_caller_(r.ptr_caller_) {
299 r.ptr_ = nullptr;
300 }
297 301
298 // Move conversion constructor. 302 // Move conversion constructor.
299 template <typename U, 303 template <typename U,
300 typename = typename std::enable_if< 304 typename = typename std::enable_if<
301 std::is_convertible<U*, T*>::value>::type> 305 std::is_convertible<U*, T*>::value>::type>
302 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { 306 scoped_refptr(scoped_refptr<U>&& r)
307 : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) {
303 r.ptr_ = nullptr; 308 r.ptr_ = nullptr;
304 } 309 }
305 310
306 ~scoped_refptr() { 311 ~scoped_refptr() {
307 if (ptr_) 312 if (ptr_)
308 Release(ptr_); 313 ptr_caller_(ptr_, PtrCall::Release);
309 } 314 }
310 315
311 T* get() const { return ptr_; } 316 T* get() const { return ptr_; }
312 317
313 T& operator*() const { 318 T& operator*() const {
314 assert(ptr_ != nullptr); 319 assert(ptr_ != nullptr);
315 return *ptr_; 320 return *ptr_;
316 } 321 }
317 322
318 T* operator->() const { 323 T* operator->() const {
319 assert(ptr_ != nullptr); 324 assert(ptr_ != nullptr);
320 return ptr_; 325 return ptr_;
321 } 326 }
322 327
323 scoped_refptr<T>& operator=(T* p) { 328 scoped_refptr<T>& operator=(T* p) {
324 // AddRef first so that self assignment should work 329 Assign(p, &PtrCallerImpl);
325 if (p)
326 AddRef(p);
327 T* old_ptr = ptr_;
328 ptr_ = p;
329 if (old_ptr)
330 Release(old_ptr);
331 return *this; 330 return *this;
332 } 331 }
333 332
334 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { 333 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
335 return *this = r.ptr_; 334 Assign(r.ptr_, r.ptr_caller_);
335 return *this;
336 } 336 }
337 337
338 template <typename U> 338 template <typename U>
339 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { 339 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
340 return *this = r.get(); 340 Assign(r.get(), &PtrCallerImpl);
341 return *this;
341 } 342 }
342 343
343 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { 344 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
344 scoped_refptr<T>(std::move(r)).swap(*this); 345 scoped_refptr<T>(std::move(r)).swap(*this);
345 return *this; 346 return *this;
346 } 347 }
347 348
348 template <typename U> 349 template <typename U>
349 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { 350 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
350 scoped_refptr<T>(std::move(r)).swap(*this); 351 scoped_refptr<T>(std::move(r)).swap(*this);
351 return *this; 352 return *this;
352 } 353 }
353 354
354 void swap(T** pp) { 355 void swap(T** pp) {
355 T* p = ptr_; 356 T* p = ptr_;
356 ptr_ = *pp; 357 ptr_ = *pp;
358 ptr_caller_ = &PtrCallerImpl;
357 *pp = p; 359 *pp = p;
358 } 360 }
359 361
360 void swap(scoped_refptr<T>& r) { 362 void swap(scoped_refptr<T>& r) {
361 swap(&r.ptr_); 363 std::swap(ptr_, r.ptr_);
364 std::swap(ptr_caller_, r.ptr_caller_);
362 } 365 }
363 366
364 explicit operator bool() const { return ptr_ != nullptr; } 367 explicit operator bool() const { return ptr_ != nullptr; }
365 368
366 template <typename U> 369 template <typename U>
367 bool operator==(const scoped_refptr<U>& rhs) const { 370 bool operator==(const scoped_refptr<U>& rhs) const {
368 return ptr_ == rhs.get(); 371 return ptr_ == rhs.get();
369 } 372 }
370 373
371 template <typename U> 374 template <typename U>
372 bool operator!=(const scoped_refptr<U>& rhs) const { 375 bool operator!=(const scoped_refptr<U>& rhs) const {
373 return !operator==(rhs); 376 return !operator==(rhs);
374 } 377 }
375 378
376 template <typename U> 379 template <typename U>
377 bool operator<(const scoped_refptr<U>& rhs) const { 380 bool operator<(const scoped_refptr<U>& rhs) const {
378 return ptr_ < rhs.get(); 381 return ptr_ < rhs.get();
379 } 382 }
380 383
381 protected: 384 protected:
385 enum class PtrCall { AddRef, Release };
386 using PtrCallerFunction = void (*)(T* ptr, PtrCall call);
387
388 static void PtrCallerImpl(T* ptr, PtrCall call) {
389 switch (call) {
390 case PtrCall::AddRef:
391 ptr->AddRef();
392 break;
393 case PtrCall::Release:
394 ptr->Release();
395 break;
396 }
397 }
398
382 T* ptr_ = nullptr; 399 T* ptr_ = nullptr;
400 PtrCallerFunction ptr_caller_ = nullptr;
383 401
384 private: 402 private:
385 // Friend required for move constructors that set r.ptr_ to null.
386 template <typename U> 403 template <typename U>
387 friend class scoped_refptr; 404 friend class scoped_refptr;
388 405
389 // Non-inline helpers to allow: 406 void Assign(T* p, PtrCallerFunction caller) {
390 // class Opaque; 407 // AddRef first so that self assignment should work
391 // extern template class scoped_refptr<Opaque>; 408 if (p)
392 // Otherwise the compiler will complain that Opaque is an incomplete type. 409 caller(p, PtrCall::AddRef);
393 static void AddRef(T* ptr); 410 T* old_ptr = ptr_;
394 static void Release(T* ptr); 411 PtrCallerFunction old_caller = ptr_caller_;
412 ptr_ = p;
413 ptr_caller_ = caller;
414 if (old_ptr)
415 old_caller(old_ptr, PtrCall::Release);
416 // Release above can potentially delete this object
417 }
395 }; 418 };
396 419
397 // static
398 template <typename T>
399 void scoped_refptr<T>::AddRef(T* ptr) {
400 ptr->AddRef();
401 }
402
403 // static
404 template <typename T>
405 void scoped_refptr<T>::Release(T* ptr) {
406 ptr->Release();
407 }
408
409 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without 420 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
410 // having to retype all the template arguments 421 // having to retype all the template arguments
411 template <typename T> 422 template <typename T>
412 scoped_refptr<T> make_scoped_refptr(T* t) { 423 scoped_refptr<T> make_scoped_refptr(T* t) {
413 return scoped_refptr<T>(t); 424 return scoped_refptr<T>(t);
414 } 425 }
415 426
416 template <typename T, typename U> 427 template <typename T, typename U>
417 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) { 428 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
418 return lhs.get() == rhs; 429 return lhs.get() == rhs;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { 463 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
453 return !operator==(null, rhs); 464 return !operator==(null, rhs);
454 } 465 }
455 466
456 template <typename T> 467 template <typename T>
457 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { 468 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
458 return out << p.get(); 469 return out << p.get();
459 } 470 }
460 471
461 #endif // BASE_MEMORY_REF_COUNTED_H_ 472 #endif // BASE_MEMORY_REF_COUNTED_H_
OLDNEW
« no previous file with comments | « no previous file | base/test/opaque_ref_counted.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698