On 7/16/19 8:28 AM, Soviet_Mario wrote:
> On 16/07/19 03:12, James Kuyper wrote:
>> On 7/15/19 7:18 PM, Soviet_Mario wrote:
>>> On 16/07/19 00:40, Öö Tiib wrote:
>>>> On Tuesday, 16 July 2019 01:01:03 UTC+3, Soviet_Mario wrote:
...
>> The standard term that matches what you mean is "non-static data member"
>> (12.2p3). Note that the storage duration of a non-static data member is
>> always the same as the storage duration of the containing object
>> (6.7.5p1). Non-static data members can therefore have static, automatic,
>> dynamic, or thread storage duration.
>
> could you give me a reference of the manual you are
> referring to with the notation "12.2p3" etc ?
> I mean a reference to some online manual
It's not a "manual", it's n4659.pdf, a free draft version of the C++
standard: the draft is almost exactly the same as the official C++2017
standard, so it's hard for me to justify paying the significant extra
cost of buying the actual standard. You can find it at
<
http://www.open-std.org/jtc1/sc22/wg21/docs/standards>
...
>> A member is not dynamically allocated unless it is a non-static data
>> member of a dynamically allocated object, in which case all non-static
>> data members of the same object are dynamically allocated.
>
> I am referring to objects of a class derived from MyString,
> that have some automatic and / or static data members,
Will you please stop using "automatic" for that purpose? The correct
term is "non-static". Given the following declarations, occurring inside
a function body:
MyString Automatic;
MyString *Dynamic = new MyString();
static MyString Static;
thread_local MyString ThreadLocal;
and assuming that MyString contains a non-static data member named
"data", then Automatic.data has automatic storage duration,
Dynamic->data has dynamic storage duration, Static.data has static
storage duration, and ThreadLocal.data has thread local storage
duration. Being "automatic" is NOT a characteristic of the "data"
member, only of it's containing object.
If that member is a pointer to dynamically allocated memory, then *data
has dynamic storage duration, regardless of what storage duration data
itself has.
...
> So I was asking about the behaviour of returning data for
> these objects whose memory "footprint" is hybrid and also
> variable depending on context.
>
> I need to understand of glvalue and grvalue, as I can only
> recall the concepts of R-value and L-value, to one side, and
> value-types vs reference-types on the other, but I surely
> have to complete the definitions I understand
glvalue and prvalue are refinements of the concepts of l-value and
r-value, respectively. Frankly, I haven't fully familiarized myself with
the details of that refinement.
...
>> of the objects that they point at, any pointer can point at any suitable
>> object, regardless of that object's storage duration.
>
> ok, but my doubt was about : is it dynamic memory
> automatically duplicated (skeptic) ?
No.
> Is NEVER duplicated ?
It's duplicated whenever you explicitly write code duplicating it.
> (harmful). Is the whole regulated by invoking the
> COPY-constructor, so that it can decide ?
Only if you explicitly define the copy-constructor, and your
user-written copy constructor makes that decision.
For example, there is a strategy, called Copy-On-Write (COW), which
means that all direct copying, whether by assignment, construction, or
conversion, involves copying over only a pointer to the actual memory
being managed. As a result, a single block of memory might be shared
between many different containers. However, as soon as a write needs to
be done, the container in which the write occurred would copy the shared
memory to a new location, and then stop participating in the share. Only
then would it write to the new location.
That's all managed by user-written code - default constructors and
default assignment operator overloads never do anything that sophisticated.
I gather that COW used to be common in implementations of std::string,
but that it has since gone out of favor. My purpose in bringing it up is
only to point out that there are more sophisticated alternatives to your
simple shallow/deep copy distinction.
>> Therefore, it's
>> not appropriate for the compiler to automatically free the memory a
>> pointer points at.
>
> yes, but my doubt was more limited, I try to repeat it.
>
> In the CALLEE, building a return value (passed not by
> address or reference, just by-value => an hint to copy
> data), some dynamic allocation is done explicitly.
> The copy received by the caller, then would ...
> 1) receive NO data at all (I'm not saying the compiler has
> ever freed it, simply it remains lost, inaccessible,
> resultin in a leak)
No.
> 2) receive a link to the same content, copied in another pointer
If the object contains a pointer to the content, then a default
constructor or a default assignment operator overload will simply copy
that pointer.
> 3) receive a copy of the dynamic data placed elsewhere
In order to get that behavior, you have to define your own non-default
constructors and non-default assignment operator overloads.
...
>> It is the responsibility of the programmer, to make
>> sure that the memory it points at is in fact deallocated, when
>> appropriate,
>
> and this is managed now overloading operator = and also in
> the copy constructor.
> It would be safe but inefficient to have this same code when
> returning objects by value that were just built (in the case
> of initialization it would be inevitable instead, as there
> is no such duplicated operation)
You misunderstand: returning objects by value is NOT a separate kind of
operation. It is performed by using constructors - a copy constructor is
sometime necessary; but constructing the return value directly in it's
final location is often a permitted optimization. What happens depends
entirely upon what you've defined those functions to do, or if you've
let them be defined by default, it depends upon what the default
versions do.
>> and only if it was dynamically allocated. That's one of the
>> things that user-defined destructors are used for - to make sure the
>> memory is deallocated.
>>
>> Smart pointers are specialized classes that have destructors that, in
>> some cases, automatically deallocate the memory that they contain a
>> pointer to.
>
> I don't master them at all .... by now I prefer to just
> resort to things I understand well.
I recommend learning about smart pointers when you have time, but I also
agree that you should not use them until you've had time to learn about
them.
> And C++ has changed very very much in 10-15 years I had
> almost abandoned it :\
Among the most important changes that are relevant to this discussion is
"move" semantics. I'm not fully up to speed on move semantics, but my
understanding is that if you move one string into another string, only
the pointer to the contained data is copied, not the data itself, and
the original string ends up empty. The actual semantics of "move"
depends upon how you define move constructors or move assignment
operator overloads. As a general rule, if it is permissible to leave the
source empty, doing a move rather than a copy is usually more efficient,
and seldom less efficient.