Pergunta

I am pretty new to C++. I have been thought shared_ptr is keeping separated pointer to separate reference-counter variable. But today, I suddenly realized actually I don't know how it laid out, and the reference-value doesn't need to have separated pointer in C++.

If the layout is defined by standard, what's is correct expected layout of std::shared_ptr?

Foi útil?

Solução

The C++ Standard does not define for any non-standard-layout class how it should be laid out in memory, e.g. [class.mem]/13

Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

There are some exceptions / simplifications for standard layout types, but there's no general specification for the memory layout of classes.

This also holds for the classes in the Standard Library. In addition to that, the Standard only defines requirements for these classes, some of those are "interfaces" in the sense of signatures of member functions. Very explicitly in [objects.within.classes]:

1) Clauses 18 through 30 and Annex D [i.e. the Standard Library] do not specify the representation of classes, and intentionally omit specification of class members (9.2). An implementation may define static or non-static class members, or both, as needed to implement the semantics of the member functions specified in Clauses 18 through 30 and Annex D.

2) Objects of certain classes are sometimes required by the external specifications of their classes to store data, apparently in member objects. For the sake of exposition, some subclauses provide representative declarations, and semantic requirements, for private member objects of classes that meet the external specifications of the classes. The declarations for such member objects and the definitions of related member types are followed by a comment that ends with exposition only, as in:

streambuf* sb; // exposition only

That said, some remarks for required functionality for std::shared_ptr:

  • you need to store the reference count for the owned object, in a dynamically allocated object which contains this ownership information (dyn. alloc. because it's not clear which shared_ptr is the last one alive, and this last one has to deallocate it)
  • you also need to store the reference count of this ownership information object for the use of weak_ptr, as weak_ptr::expired and weak_ptr::lock etc. may not fail (via an access violation, for example)

Pedantic side remark: The Standard doesn't require shared_ptr not to leak memory, but a typical implementation for PC-type architecture will probably use dynamic memory allocation.

std::make_shared btw is considered to be faster than using the ctor of std::shared_ptr because it can allocate the memory for both the owned object and the ownership information object in one allocation (the Standard says "Implementations should perform no more than one memory allocation.", though that is only a Remark).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top