A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
object.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007 INRIA, Gustavo Carneiro
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
7 * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 */
9#ifndef OBJECT_H
10#define OBJECT_H
11
13#include "attribute.h"
14#include "object-base.h"
15#include "ptr.h"
16#include "simple-ref-count.h"
17
18#include <stdint.h>
19#include <string>
20#include <vector>
21
22/**
23 * \file
24 * \ingroup object
25 * ns3::Object class declaration, which is the root of the Object hierarchy
26 * and Aggregation.
27 */
28
29namespace ns3
30{
31
32class Object;
33class AttributeAccessor;
34class AttributeValue;
35class TraceSourceAccessor;
36
37/**
38 * \ingroup core
39 * \defgroup object Object
40 * \brief Base classes which provide memory management and object aggregation.
41 */
42
43/**
44 * \ingroup object
45 * \ingroup ptr
46 * Standard Object deleter, used by SimpleRefCount
47 * to delete an Object when the reference count drops to zero.
48 */
50{
51 /**
52 * Smart pointer deleter implementation for Object.
53 *
54 * Delete implementation, forwards to the Object::DoDelete()
55 * method.
56 *
57 * \param [in] object The Object to delete.
58 */
59 inline static void Delete(Object* object);
60};
61
62/**
63 * \ingroup object
64 * \brief A base class which provides memory management and object aggregation
65 *
66 * The memory management scheme is based on reference-counting with
67 * dispose-like functionality to break the reference cycles.
68 * The reference count is incremented and decremented with
69 * the methods Ref() and Unref(). If a reference cycle is
70 * present, the user is responsible for breaking it
71 * by calling Dispose() in a single location. This will
72 * eventually trigger the invocation of DoDispose() on itself and
73 * all its aggregates. The DoDispose() method is always automatically
74 * invoked from the Unref() method before destroying the Object,
75 * even if the user did not call Dispose() directly.
76 */
77class Object : public SimpleRefCount<Object, ObjectBase, ObjectDeleter>
78{
79 public:
80 /**
81 * \brief Register this type.
82 * \return The Object TypeId.
83 */
84 static TypeId GetTypeId();
85
86 /**
87 * \brief Iterate over the Objects aggregated to an ns3::Object.
88 *
89 * This iterator does not allow you to iterate over the parent
90 * Object used to call Object::GetAggregateIterator.
91 *
92 * \note This is a java-style iterator.
93 */
95 {
96 public:
97 /** Default constructor, which has no Object. */
99
100 /**
101 * Check if there are more Aggregates to iterate over.
102 *
103 * \returns \c true if Next() can be called and return a non-null
104 * pointer, \c false otherwise.
105 */
106 bool HasNext() const;
107
108 /**
109 * Get the next Aggregated Object.
110 *
111 * \returns The next aggregated Object.
112 */
114
115 private:
116 /** Object needs access. */
117 friend class Object;
118 /**
119 * Construct from an Object.
120 *
121 * This is private, with Object as friend, so only Objects can create
122 * useful AggregateIterators.
123 *
124 * \param [in] object The Object whose Aggregates should be iterated over.
125 */
127 Ptr<const Object> m_object; //!< Parent Object.
128 uint32_t m_current; //!< Current position in parent's aggregates.
129 /// Iterator to the unidirectional aggregates.
130 std::vector<Ptr<Object>>::const_iterator m_uniAggrIter;
131 };
132
133 /** Constructor. */
134 Object();
135 /** Destructor. */
136 ~Object() override;
137
138 TypeId GetInstanceTypeId() const override;
139
140 /**
141 * Get a pointer to the requested aggregated Object. If the type of object
142 * requested is ns3::Object, a Ptr to the calling object is returned.
143 *
144 * \tparam T \explicit The type of the aggregated Object to retrieve.
145 * \returns A pointer to the requested Object, or zero
146 * if it could not be found.
147 */
148 template <typename T>
149 inline Ptr<T> GetObject() const;
150 /**
151 * Get a pointer to the requested aggregated Object by TypeId. If the
152 * TypeId argument is ns3::Object, a Ptr to the calling object is returned.
153 *
154 * \tparam T \explicit The type of the aggregated Object to retrieve.
155 * \param [in] tid The TypeId of the requested Object.
156 * \returns A pointer to the requested Object with the specified TypeId,
157 * or zero if it could not be found.
158 */
159 template <typename T>
160 Ptr<T> GetObject(TypeId tid) const;
161 /**
162 * Dispose of this Object.
163 *
164 * Run the DoDispose() methods of this Object and all the
165 * Objects aggregated to it.
166 * After calling this method, this Object is expected to be
167 * totally unusable except for the Ref() and Unref() methods.
168 *
169 * \note You can call Dispose() many times on the same Object or
170 * different Objects aggregated together, and DoDispose() will be
171 * called only once for each aggregated Object.
172 *
173 * This method is typically used to break reference cycles.
174 */
175 void Dispose();
176 /**
177 * Aggregate two Objects together.
178 *
179 * \param [in] other The other Object pointer
180 *
181 * This method aggregates the two Objects together: after this
182 * method returns, it becomes possible to call GetObject()
183 * on one to get the other, and vice-versa.
184 *
185 * This method calls the virtual method NotifyNewAggregates() to
186 * notify all aggregated Objects that they have been aggregated
187 * together.
188 *
189 * \sa NotifyNewAggregate()
190 */
191 void AggregateObject(Ptr<Object> other);
192
193 /**
194 * Aggregate an Object to another Object.
195 *
196 * \param [in] other The other Object pointer
197 *
198 * This method aggregates the an object to another Object:
199 * after this method returns, it becomes possible to call GetObject()
200 * on the aggregating Object to get the other, but not vice-versa.
201 *
202 * This method calls the virtual method NotifyNewAggregates() to
203 * notify all aggregated Objects that they have been aggregated
204 * together.
205 *
206 * This method is useful only if there is the need to aggregate an
207 * object to more than one object at the same time, and should be avoided
208 * if not strictly necessary.
209 * In particular, objects aggregated with this method should be destroyed
210 * only after making sure that the objects they are aggregated to are
211 * destroyed as well. However, the destruction of the aggregating objects
212 * will take care of the unidirectional aggregated objects gracefully.
213 *
214 * Beware that an object aggregated to another with this function
215 * behaves differently than other aggregates in the following ways.
216 * Suppose that Object B is aggregated unidirectionally:
217 * - It can be aggregated unidirectionally to more than one objects
218 * (e.g., A1 and A2).
219 * - It is not possible to call GetObject on B to find an aggregate of
220 * object A1 or A2.
221 * - When A1 or A2 are initialized, B is initialized, whichever happens first.
222 * - When A1 or A2 are destroyed, B is destroyed, whichever happens last.
223 * - If B is initialized, A1 and A2 are unaffected.
224 * - If B is forcefully destroyed, A1 and A2 are unaffected.
225 *
226 *
227 * \sa AggregateObject()
228 */
230
231 /**
232 * Get an iterator to the Objects aggregated to this one.
233 *
234 * \returns An iterator to the first Object aggregated to this
235 * Object.
236 *
237 * If no Objects are aggregated to this Object, then, the returned
238 * iterator will be empty and AggregateIterator::HasNext() will
239 * always return \c false.
240 */
242
243 /**
244 * Invoke DoInitialize on all Objects aggregated to this one.
245 *
246 * This method calls the virtual DoInitialize() method on all the Objects
247 * aggregated to this Object. DoInitialize() will be called only once over
248 * the lifetime of an Object, just like DoDispose() is called only
249 * once.
250 *
251 * \sa DoInitialize()
252 */
253 void Initialize();
254
255 /**
256 * Check if the object has been initialized.
257 *
258 * \brief Check if the object has been initialized.
259 * \returns \c true if the object has been initialized.
260 */
261 bool IsInitialized() const;
262
263 protected:
264 /**
265 * Notify all Objects aggregated to this one of a new Object being
266 * aggregated.
267 *
268 * This method is invoked whenever two sets of Objects are aggregated
269 * together. It is invoked exactly once for each Object in both sets.
270 * This method can be overridden by subclasses who wish to be notified
271 * of aggregation events. These subclasses must chain up to their
272 * base class NotifyNewAggregate() method.
273 *
274 * It is safe to call GetObject() and AggregateObject() from within
275 * this method.
276 */
277 virtual void NotifyNewAggregate();
278 /**
279 * Initialize() implementation.
280 *
281 * This method is called only once by Initialize(). If the user
282 * calls Initialize() multiple times, DoInitialize() is called only the
283 * first time.
284 *
285 * Subclasses are expected to override this method and chain up
286 * to their parent's implementation once they are done. It is
287 * safe to call GetObject() and AggregateObject() from within this method.
288 */
289 virtual void DoInitialize();
290 /**
291 * Destructor implementation.
292 *
293 * This method is called by Dispose() or by the Object's
294 * destructor, whichever comes first.
295 *
296 * Subclasses are expected to implement their real destruction
297 * code in an overridden version of this method and chain
298 * up to their parent's implementation once they are done.
299 * _i.e_, for simplicity, the destructor of every subclass should
300 * be empty and its content should be moved to the associated
301 * DoDispose() method.
302 *
303 * It is safe to call GetObject() from within this method.
304 */
305 virtual void DoDispose();
306 /**
307 * Copy an Object.
308 *
309 * \param [in] o the Object to copy.
310 *
311 * Allow subclasses to implement a copy constructor.
312 *
313 * While it is technically possible to implement a copy
314 * constructor in a subclass, we strongly discourage you
315 * from doing so. If you really want to do it anyway, you have
316 * to understand that this copy constructor will _not_
317 * copy aggregated Objects, _i.e_, if your Object instance
318 * is already aggregated to another Object and if you invoke
319 * this copy constructor, the new Object instance will be
320 * a pristine standalone Object instance not aggregated to
321 * any other Object. It is thus _your_ responsibility
322 * as a caller of this method to do what needs to be done
323 * (if it is needed) to ensure that the Object stays in a
324 * valid state.
325 */
326 Object(const Object& o);
327
328 private:
329 /**
330 * Copy an Object.
331 *
332 * \tparam T \deduced The type of the Object being copied.
333 * \param [in] object A pointer to the object to copy.
334 * \returns A copy of the input object.
335 *
336 * This method invoke the copy constructor of the input object
337 * and returns the new instance.
338 */
339 /**@{*/
340 template <typename T>
341 friend Ptr<T> CopyObject(Ptr<T> object);
342 template <typename T>
343 friend Ptr<T> CopyObject(Ptr<const T> object);
344 /**@}*/
345
346 /**
347 * Set the TypeId and construct all Attributes of an Object.
348 *
349 * \tparam T \deduced The type of the Object to complete.
350 * \param [in] object The uninitialized object pointer.
351 * \return The derived object.
352 */
353 template <typename T>
354 friend Ptr<T> CompleteConstruct(T* object);
355
356 /** Friends. @{*/
357 friend class ObjectFactory;
358 friend class AggregateIterator;
359 friend struct ObjectDeleter;
360
361 /**@}*/
362
363 /**
364 * The list of Objects aggregated to this one.
365 *
366 * This data structure uses a classic C-style trick to
367 * hold an array of variable size without performing
368 * two memory allocations: the declaration of the structure
369 * declares a one-element array but when we allocate
370 * memory for this struct, we effectively allocate a larger
371 * chunk of memory than the struct to allow space for a larger
372 * variable sized buffer whose size is indicated by the element
373 * \c n
374 */
376 {
377 /** The number of entries in \c buffer. */
379 /** The array of Objects. */
381 };
382
383 /**
384 * Find an Object of TypeId tid in the aggregates of this Object.
385 *
386 * \param [in] tid The TypeId we're looking for
387 * \return The matching Object, if it is found
388 */
389 Ptr<Object> DoGetObject(TypeId tid) const;
390 /**
391 * Verify that this Object is still live, by checking it's reference count.
392 * \return \c true if the reference count is non zero.
393 */
394 bool Check() const;
395 /**
396 * Check if any aggregated Objects have non-zero reference counts.
397 *
398 * \return \c true if any of our aggregates have non zero reference count.
399 *
400 * In some cases, when an event is scheduled against a subclass of
401 * Object, and if no one owns a reference directly to this Object, the
402 * Object is alive, has a refcount of zero and the method run when the
403 * event expires runs against the raw pointer, which means that we are
404 * manipulating an Object with a refcount of zero. So, instead we
405 * check the aggregate reference count.
406 */
407 bool CheckLoose() const;
408 /**
409 * Set the TypeId of this Object.
410
411 * \param [in] tid The TypeId value to set.
412 *
413 * Invoked from ns3::CreateObject only.
414 * Initialize the \c m_tid member variable to
415 * keep track of the type of this Object instance.
416 */
417 void SetTypeId(TypeId tid);
418 /**
419 * Initialize all member variables registered as Attributes of this TypeId.
420 *
421 * \param [in] attributes The attribute values used to initialize
422 * the member variables of this Object's instance.
423 *
424 * Invoked from ns3::ObjectFactory::Create and ns3::CreateObject only.
425 * Initialize all the member variables which were
426 * registered with the associated TypeId.
427 */
428 void Construct(const AttributeConstructionList& attributes);
429
430 /**
431 * Keep the list of aggregates in most-recently-used order
432 *
433 * \param [in,out] aggregates The list of aggregated Objects.
434 * \param [in] i The most recently used entry in the list.
435 */
436 void UpdateSortedArray(Aggregates* aggregates, uint32_t i) const;
437 /**
438 * Attempt to delete this Object.
439 *
440 * This method iterates over all aggregated Objects to check if they all
441 * have a zero refcount. If yes, the Object and all
442 * its aggregates are deleted. If not, nothing is done.
443 */
444 void DoDelete();
445
446 /**
447 * Identifies the type of this Object instance.
448 */
450 /**
451 * Set to \c true when the DoDispose() method of the Object has run,
452 * \c false otherwise.
453 */
455 /**
456 * Set to \c true once the DoInitialize() method has run,
457 * \c false otherwise
458 */
460 /**
461 * A pointer to an array of 'aggregates'.
462 *
463 * A pointer to each Object aggregated to this Object is stored in this
464 * array. The array is shared by all aggregated Objects
465 * so the size of the array is indirectly a reference count.
466 */
468
469 /**
470 * An array of unidirectional aggregates, i.e., objects that are
471 * aggregated to the current object, but not vice-versa.
472 *
473 * This is useful (and suggested) only for Objects that should
474 * be aggregated to multiple other Objects, where the normal
475 * Aggregation would create an issue.
476 */
477 std::vector<Ptr<Object>> m_unidirectionalAggregates;
478
479 /**
480 * The number of times the Object was accessed with a
481 * call to GetObject().
482 *
483 * This integer is used to implement a heuristic to sort
484 * the array of aggregates in most-frequently accessed order.
485 */
487};
488
489template <typename T>
491template <typename T>
492Ptr<T> CopyObject(Ptr<T> object);
493
494} // namespace ns3
495
496namespace ns3
497{
498
499/*************************************************************************
500 * The Object implementation which depends on templates
501 *************************************************************************/
502
503void
505{
506 object->DoDelete();
507}
508
509template <typename T>
510Ptr<T>
512{
513 // This is an optimization: if the cast works (which is likely),
514 // things will be pretty fast.
515 T* result = dynamic_cast<T*>(m_aggregates->buffer[0]);
516 if (result != nullptr)
517 {
518 return Ptr<T>(result);
519 }
520 // if the cast does not work, we try to do a full type check.
521 Ptr<Object> found = DoGetObject(T::GetTypeId());
522 if (found)
523 {
524 return Ptr<T>(static_cast<T*>(PeekPointer(found)));
525 }
526 return nullptr;
527}
528
529/**
530 * Specialization of \link Object::GetObject () \endlink for
531 * objects of type ns3::Object.
532 *
533 * \returns A Ptr to the calling object.
534 */
535template <>
536inline Ptr<Object>
538{
539 return Ptr<Object>(const_cast<Object*>(this));
540}
541
542template <typename T>
543Ptr<T>
545{
546 Ptr<Object> found = DoGetObject(tid);
547 if (found)
548 {
549 return Ptr<T>(static_cast<T*>(PeekPointer(found)));
550 }
551 return nullptr;
552}
553
554/**
555 * Specialization of \link Object::GetObject (TypeId tid) \endlink for
556 * objects of type ns3::Object.
557 *
558 * \param [in] tid The TypeId of the requested Object.
559 * \returns A Ptr to the calling object.
560 */
561template <>
562inline Ptr<Object>
564{
565 if (tid == Object::GetTypeId())
566 {
567 return Ptr<Object>(const_cast<Object*>(this));
568 }
569 else
570 {
571 return DoGetObject(tid);
572 }
573}
574
575/*************************************************************************
576 * The helper functions which need templates.
577 *************************************************************************/
578
579template <typename T>
580Ptr<T>
582{
583 Ptr<T> p = Ptr<T>(new T(*PeekPointer(object)), false);
584 NS_ASSERT(p->GetInstanceTypeId() == object->GetInstanceTypeId());
585 return p;
586}
587
588template <typename T>
589Ptr<T>
591{
592 Ptr<T> p = Ptr<T>(new T(*PeekPointer(object)), false);
593 NS_ASSERT(p->GetInstanceTypeId() == object->GetInstanceTypeId());
594 return p;
595}
596
597template <typename T>
598Ptr<T>
600{
601 object->SetTypeId(T::GetTypeId());
602 object->Object::Construct(AttributeConstructionList());
603 return Ptr<T>(object, false);
604}
605
606/**
607 * \ingroup object
608 * @{
609 */
610/**
611 * Create an object by type, with varying number of constructor parameters.
612 *
613 * \tparam T \explicit The type of the derived object to construct.
614 * \param [in] args Arguments to pass to the constructor.
615 * \return The derived object.
616 */
617template <typename T, typename... Args>
618Ptr<T>
619CreateObject(Args&&... args)
620{
621 return CompleteConstruct(new T(std::forward<Args>(args)...));
622}
623
624/**@}*/
625
626} // namespace ns3
627
628#endif /* OBJECT_H */
ns3::AttributeConstructionList declaration.
ns3::AttributeValue, ns3::AttributeAccessor and ns3::AttributeChecker declarations.
List of Attribute name, value and checker triples used to construct Objects.
Iterate over the Objects aggregated to an ns3::Object.
Definition object.h:95
std::vector< Ptr< Object > >::const_iterator m_uniAggrIter
Iterator to the unidirectional aggregates.
Definition object.h:130
Ptr< const Object > Next()
Get the next Aggregated Object.
Definition object.cc:56
Ptr< const Object > m_object
Parent Object.
Definition object.h:127
AggregateIterator()
Default constructor, which has no Object.
Definition object.cc:40
uint32_t m_current
Current position in parent's aggregates.
Definition object.h:128
bool HasNext() const
Check if there are more Aggregates to iterate over.
Definition object.cc:48
Instantiate subclasses of ns3::Object.
A base class which provides memory management and object aggregation.
Definition object.h:78
Aggregates * m_aggregates
A pointer to an array of 'aggregates'.
Definition object.h:467
void UnidirectionalAggregateObject(Ptr< Object > other)
Aggregate an Object to another Object.
Definition object.cc:368
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition object.cc:203
friend Ptr< T > CopyObject(Ptr< T > object)
Copy an Object.
Definition object.h:581
void UpdateSortedArray(Aggregates *aggregates, uint32_t i) const
Keep the list of aggregates in most-recently-used order.
Definition object.cc:284
void Construct(const AttributeConstructionList &attributes)
Initialize all member variables registered as Attributes of this TypeId.
Definition object.cc:146
bool Check() const
Verify that this Object is still live, by checking it's reference count.
Definition object.cc:447
Ptr< Object > DoGetObject(TypeId tid) const
Find an Object of TypeId tid in the aggregates of this Object.
Definition object.cc:153
bool m_disposed
Set to true when the DoDispose() method of the Object has run, false otherwise.
Definition object.h:454
std::vector< Ptr< Object > > m_unidirectionalAggregates
An array of unidirectional aggregates, i.e., objects that are aggregated to the current object,...
Definition object.h:477
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:412
bool CheckLoose() const
Check if any aggregated Objects have non-zero reference counts.
Definition object.cc:461
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
~Object() override
Destructor.
Definition object.cc:108
AggregateIterator GetAggregateIterator() const
Get an iterator to the Objects aggregated to this one.
Definition object.cc:418
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:440
void SetTypeId(TypeId tid)
Set the TypeId of this Object.
Definition object.cc:425
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:298
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
Definition object.cc:83
static TypeId GetTypeId()
Register this type.
Definition object.cc:90
void Dispose()
Dispose of this Object.
Definition object.cc:247
TypeId m_tid
Identifies the type of this Object instance.
Definition object.h:449
Object()
Constructor.
Definition object.cc:96
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:240
uint32_t m_getObjectCount
The number of times the Object was accessed with a call to GetObject().
Definition object.h:486
friend Ptr< T > CompleteConstruct(T *object)
Set the TypeId and construct all Attributes of an Object.
Definition object.h:599
void DoDelete()
Attempt to delete this Object.
Definition object.cc:479
bool m_initialized
Set to true once the DoInitialize() method has run, false otherwise.
Definition object.h:459
Smart pointer class similar to boost::intrusive_ptr.
A template-based reference counting class.
a unique identifier for an interface.
Definition type-id.h:48
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
Ptr< T > CopyObject(Ptr< const T > object)
Definition object.h:581
Ptr< T > CompleteConstruct(T *object)
Definition object.h:599
ns3::ObjectBase declaration and NS_OBJECT_ENSURE_REGISTERED() macro definition.
ns3::Ptr smart pointer declaration and implementation.
ns3::SimpleRefCount declaration and template implementation.
The list of Objects aggregated to this one.
Definition object.h:376
uint32_t n
The number of entries in buffer.
Definition object.h:378
Object * buffer[1]
The array of Objects.
Definition object.h:380
Standard Object deleter, used by SimpleRefCount to delete an Object when the reference count drops to...
Definition object.h:50
static void Delete(Object *object)
Smart pointer deleter implementation for Object.
Definition object.h:504