deal.II version GIT relicensing-1838-g97284be5cd 2024-09-11 15:30:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
smartpointer.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 1998 - 2023 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_smartpointer_h
16#define dealii_smartpointer_h
17
18
19#include <deal.II/base/config.h>
20
23
24#include <atomic>
25#include <typeinfo>
26
28
102template <typename T, typename P = void>
104{
105public:
111
116 template <class Q>
118
124
129
138 SmartPointer(T *t, const std::string &id);
139
147
152
160 operator=(T *tt);
161
166 template <class Q>
169
176
181 operator=(SmartPointer<T, P> &&other) noexcept;
182
194 void
196
200 operator T *() const;
201
206 T &
207 operator*() const;
208
213 T *
214 get() const;
215
220 T *
221 operator->() const;
222
232 template <class Q>
233 void
235
244 void
245 swap(T *&ptr);
246
252 std::size_t
254
255private:
260
264 const std::string id;
265
270 std::atomic<bool> pointed_to_object_is_alive;
271};
272
273
274/* --------------------- inline Template functions ------------------------- */
275
276
277template <typename T, typename P>
279 : pointer(nullptr)
280 , id(typeid(P).name())
281 , pointed_to_object_is_alive(false)
282{
283 static_assert(std::is_base_of_v<Subscriptor, T>,
284 "This class can only be used if the first template argument "
285 "is a class derived from 'Subscriptor'.");
286}
287
288
289
290template <typename T, typename P>
292 : pointer(t)
293 , id(typeid(P).name())
294 , pointed_to_object_is_alive(false)
295{
296 static_assert(std::is_base_of_v<Subscriptor, T>,
297 "This class can only be used if the first template argument "
298 "is a class derived from 'Subscriptor'.");
299
300 if (t != nullptr)
301 t->subscribe(&pointed_to_object_is_alive, id);
302}
303
304
305
306template <typename T, typename P>
307inline SmartPointer<T, P>::SmartPointer(T *t, const std::string &id)
308 : pointer(t)
309 , id(id)
310 , pointed_to_object_is_alive(false)
311{
312 static_assert(std::is_base_of_v<Subscriptor, T>,
313 "This class can only be used if the first template argument "
314 "is a class derived from 'Subscriptor'.");
315
316 if (pointer != nullptr)
317 pointer->subscribe(&pointed_to_object_is_alive, id);
318}
319
320
321
322template <typename T, typename P>
323template <class Q>
325 : pointer(other.pointer)
326 , id(other.id)
327 , pointed_to_object_is_alive(false)
328{
329 static_assert(std::is_base_of_v<Subscriptor, T>,
330 "This class can only be used if the first template argument "
331 "is a class derived from 'Subscriptor'.");
332
333 if (other != nullptr)
334 {
336 ExcMessage("You can't copy a smart pointer object that "
337 "is pointing to an object that is no longer alive."));
338 pointer->subscribe(&pointed_to_object_is_alive, id);
339 }
340}
341
342
343
344template <typename T, typename P>
346 : pointer(other.pointer)
347 , id(other.id)
348 , pointed_to_object_is_alive(false)
349{
350 static_assert(std::is_base_of_v<Subscriptor, T>,
351 "This class can only be used if the first template argument "
352 "is a class derived from 'Subscriptor'.");
353
354 if (other != nullptr)
355 {
357 ExcMessage("You can't copy a smart pointer object that "
358 "is pointing to an object that is no longer alive."));
359 pointer->subscribe(&pointed_to_object_is_alive, id);
360 }
361}
362
363
364
365template <typename T, typename P>
367 : pointer(other.pointer)
368 , id(other.id)
369 , pointed_to_object_is_alive(false)
370{
371 static_assert(std::is_base_of_v<Subscriptor, T>,
372 "This class can only be used if the first template argument "
373 "is a class derived from 'Subscriptor'.");
374
375 if (other != nullptr)
376 {
377 Assert(other.pointed_to_object_is_alive,
378 ExcMessage("You can't move a smart pointer object that "
379 "is pointing to an object that is no longer alive."));
380
381 try
382 {
383 pointer->subscribe(&pointed_to_object_is_alive, id);
384 }
385 catch (...)
386 {
387 Assert(false,
389 "Calling subscribe() failed with an exception, but we "
390 "are in a function that cannot throw exceptions. "
391 "Aborting the program here."));
392 }
393
394 // Release the rhs object as if we had moved all members away from
395 // it directly:
396 other = nullptr;
397 }
398}
399
400
401
402template <typename T, typename P>
404{
405 static_assert(std::is_base_of_v<Subscriptor, T>,
406 "This class can only be used if the first template argument "
407 "is a class derived from 'Subscriptor'.");
408
409 if (pointed_to_object_is_alive && pointer != nullptr)
410 pointer->unsubscribe(&pointed_to_object_is_alive, id);
411}
412
413
414
415template <typename T, typename P>
416inline void
418{
419 if (pointed_to_object_is_alive && pointer != nullptr)
420 {
421 pointer->unsubscribe(&pointed_to_object_is_alive, id);
422 delete pointer;
423 Assert(pointed_to_object_is_alive == false, ExcInternalError());
424 }
425 pointer = nullptr;
426}
427
428
429
430template <typename T, typename P>
431inline SmartPointer<T, P> &
433{
434 // optimize if no real action is requested
435 if (pointer == tt)
436 return *this;
437
438 // Let us unsubscribe from the current object
439 if (pointed_to_object_is_alive && pointer != nullptr)
440 pointer->unsubscribe(&pointed_to_object_is_alive, id);
441
442 // Then reset to the new object, and subscribe to it
443 pointer = tt;
444 if (tt != nullptr)
445 pointer->subscribe(&pointed_to_object_is_alive, id);
446
447 return *this;
448}
449
450
451
452template <typename T, typename P>
453template <class Q>
454inline SmartPointer<T, P> &
456{
457 // if objects on the left and right
458 // hand side of the operator= are
459 // the same, then this is a no-op
460 if (&other == this)
461 return *this;
462
463 // Let us unsubscribe from the current object
464 if (pointed_to_object_is_alive && pointer != nullptr)
465 pointer->unsubscribe(&pointed_to_object_is_alive, id);
466
467 // Then reset to the new object, and subscribe to it
468 pointer = (other != nullptr ? other.get() : nullptr);
469 if (other != nullptr)
470 {
472 ExcMessage("You can't copy a smart pointer object that "
473 "is pointing to an object that is no longer alive."));
474 pointer->subscribe(&pointed_to_object_is_alive, id);
475 }
476 return *this;
477}
478
479
480
481template <typename T, typename P>
482inline SmartPointer<T, P> &
484{
485 // if objects on the left and right
486 // hand side of the operator= are
487 // the same, then this is a no-op
488 if (&other == this)
489 return *this;
490
491 // Let us unsubscribe from the current object
492 if (pointed_to_object_is_alive && pointer != nullptr)
493 pointer->unsubscribe(&pointed_to_object_is_alive, id);
494
495 // Then reset to the new object, and subscribe to it
496 pointer = (other != nullptr ? other.get() : nullptr);
497 if (other != nullptr)
498 {
500 ExcMessage("You can't copy a smart pointer object that "
501 "is pointing to an object that is no longer alive."));
502 pointer->subscribe(&pointed_to_object_is_alive, id);
503 }
504 return *this;
505}
506
507
508
509template <typename T, typename P>
510inline SmartPointer<T, P> &
512{
513 if (other == nullptr)
514 {
515 *this = nullptr;
516 }
517 // if objects on the left and right hand side of the operator= are
518 // the same, then this is a no-op
519 else if (&other != this)
520 {
521 // Let us unsubscribe from the current object
522 if (pointer != nullptr && pointed_to_object_is_alive)
523 pointer->unsubscribe(&pointed_to_object_is_alive, id);
524
525 // Then reset to the new object, and subscribe to it:
526 Assert(other.pointed_to_object_is_alive,
527 ExcMessage("You can't move a smart pointer object that "
528 "is pointing to an object that is no longer alive."));
529 pointer = other.get();
530 try
531 {
532 pointer->subscribe(&pointed_to_object_is_alive, id);
533 }
534 catch (...)
535 {
536 Assert(false,
538 "Calling subscribe() failed with an exception, but we "
539 "are in a function that cannot throw exceptions. "
540 "Aborting the program here."));
541 }
542
543 // Finally release the rhs object since we moved its contents
544 other = nullptr;
545 }
546 return *this;
547}
548
549
550
551template <typename T, typename P>
553{
554 return pointer;
555}
556
557
558
559template <typename T, typename P>
560inline T &
562{
563 Assert(pointer != nullptr, ExcNotInitialized());
564 Assert(pointed_to_object_is_alive,
565 ExcMessage("The object pointed to is not valid anymore."));
566 return *pointer;
567}
568
569
570
571template <typename T, typename P>
572inline T *
574{
575 Assert(pointer != nullptr, ExcNotInitialized());
576 Assert(pointed_to_object_is_alive,
577 ExcMessage("The object pointed to is not valid anymore."));
578 return pointer;
579}
580
581
582
583template <typename T, typename P>
584inline T *
586{
587 return this->get();
588}
589
590
591
592template <typename T, typename P>
593template <class Q>
594inline void
596{
597#ifdef DEBUG
598 SmartPointer<T, P> aux(pointer, id);
599 *this = other;
600 other = aux;
601#else
602 std::swap(pointer, other.pointer);
603#endif
604}
605
606
607
608template <typename T, typename P>
609inline void
611{
612 if (pointed_to_object_is_alive && pointer != nullptr)
613 pointer->unsubscribe(pointed_to_object_is_alive, id);
614
615 std::swap(pointer, ptr);
616
617 if (pointer != nullptr)
618 pointer->subscribe(pointed_to_object_is_alive, id);
619}
620
621
622
623template <typename T, typename P>
624inline std::size_t
626{
627 return sizeof(SmartPointer<T, P>);
628}
629
630
631
632// The following function is not strictly necessary but is an optimization
633// for places where you call swap(p1,p2) with SmartPointer objects p1, p2.
634// Unfortunately, MS Visual Studio (at least up to the 2013 edition) trips
635// over it when calling std::swap(v1,v2) where v1,v2 are std::vectors of
636// SmartPointer objects: it can't determine whether it should call std::swap
637// or ::swap on the individual elements (see bug #184 on our Google Code
638// site. Consequently, just take this function out of the competition for this
639// compiler.
640#ifndef _MSC_VER
646template <typename T, typename P, class Q>
647inline void
649{
650 t1.swap(t2);
651}
652#endif
653
654
662template <typename T, typename P>
663inline void
665{
666 t1.swap(t2);
667}
668
669
670
678template <typename T, typename P>
679inline void
681{
682 t2.swap(t1);
683}
684
686
687#endif
const std::string id
T * operator->() const
void swap(SmartPointer< T, Q > &tt)
SmartPointer(const SmartPointer< T, Q > &other)
SmartPointer< T, P > & operator=(const SmartPointer< T, P > &other)
void swap(T *&ptr)
std::atomic< bool > pointed_to_object_is_alive
SmartPointer(const SmartPointer< T, P > &other)
std::size_t memory_consumption() const
SmartPointer< T, P > & operator=(SmartPointer< T, P > &&other) noexcept
SmartPointer< T, P > & operator=(const SmartPointer< T, Q > &other)
T * get() const
SmartPointer(T *t, const std::string &id)
SmartPointer< T, P > & operator=(T *tt)
T & operator*() const
SmartPointer(SmartPointer< T, P > &&other) noexcept
#define DEAL_II_DEPRECATED
Definition config.h:207
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:500
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:501
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
void swap(SmartPointer< T, P > &t1, SmartPointer< T, Q > &t2)