Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #67046 > unrolled thread

[niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ?

Started bySoviet_Mario <SovietMario@CCCP.MIR>
First post2019-07-16 00:00 +0200
Last post2019-07-17 07:36 +0000
Articles 18 — 6 participants

Back to article view | Back to comp.lang.c++


Contents

  [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 00:00 +0200
    Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Öö Tiib <ootiib@hot.ee> - 2019-07-15 15:40 -0700
      Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 01:18 +0200
        Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-07-15 21:12 -0400
          Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 14:28 +0200
            Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-07-16 09:47 -0400
              Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 17:16 +0200
                Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-07-16 10:30 -0700
                  Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 19:44 +0200
            Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Rosario19 <Ros@invalid.invalid> - 2019-07-23 09:28 +0200
        Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Öö Tiib <ootiib@hot.ee> - 2019-07-15 20:22 -0700
          Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 14:37 +0200
            Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Öö Tiib <ootiib@hot.ee> - 2019-07-17 01:41 -0700
    Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Paavo Helde <myfirstname@osa.pri.ee> - 2019-07-16 15:04 +0300
      Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Soviet_Mario <SovietMario@CCCP.MIR> - 2019-07-16 14:42 +0200
        Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Paavo Helde <myfirstname@osa.pri.ee> - 2019-07-16 16:15 +0300
        Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-07-16 10:07 -0400
    Re: [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ? Juha Nieminen <nospam@thanks.invalid> - 2019-07-17 07:36 +0000

#67046 — [niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ?

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 00:00 +0200
Subject[niubbo] aggregate types built in a function and returned by value (on stack). Shallow or Deep copy ?
Message-ID<qgit2g$qd3$1@dont-email.me>
I've been a long time far from C++ and I realize I have 
forgotten most, and moreover don't understand "modern" C++ 
.... anyway

When in a function (member or not is irrelevant) I build an 
aggregate object (class / struct, possibly nested with 
other), and this aggregate has a DEFAULT public constructor 
which does not resort to new or new [], but then the said 
former function invokes some class methods that DO some 
dynamic allocation, and then the function returns passing 
outside a copy by-value of the built object to the caller, 
placed "partially" on the stack, the final copy will be 
shallow or deep ?
With shallow I mean : every automatic member not requiring 
new or new [], with deep copy I mean exact copy (or even the 
temporary itself ...).

another maybe relevant detail
is it relevant whether the COPY constructor is defined or 
the default one ? How behaves a default generated copy 
constructor ? Does it perform also new/ new [] operations ?

Is it really the COPY constructor that is called on such a 
situation (returning a complex type by-value instead of 
by-pointer) ?

or a COPY constructor is given, which does not do deep copy, 
but just "automatic" data is replicated.


In case I defined a COPY constructor making dynamic 
allocation, is it : 1) required, 2) optional or 3) 
deprecated and possibly dangerous define also an explicit 
DESTRUCTOR making cleanups ?

TY

-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [next] | [standalone]


#67048

FromÖö Tiib <ootiib@hot.ee>
Date2019-07-15 15:40 -0700
Message-ID<768dccb2-7087-4abc-a430-1a7ee63e00b1@googlegroups.com>
In reply to#67046
On Tuesday, 16 July 2019 01:01:03 UTC+3, Soviet_Mario  wrote:
> I've been a long time far from C++ and I realize I have 
> forgotten most, and moreover don't understand "modern" C++ 
> .... anyway
> 
> When in a function (member or not is irrelevant) I build an 
> aggregate object (class / struct, possibly nested with 
> other), and this aggregate has a DEFAULT public constructor 
> which does not resort to new or new [], but then the said 
> former function invokes some class methods that DO some 
> dynamic allocation, and then the function returns passing 
> outside a copy by-value of the built object to the caller, 
> placed "partially" on the stack, the final copy will be 
> shallow or deep ?

Long sentence that sounded too controversial to 
understand. 1) An aggregate can't have ANY user-declared 
constructors or destructors. 2) Returning objects of class
type results with RVO (no copies made). 3) Your concept
of shallow copies is also hard to understand:

> With shallow I mean : every automatic member not requiring 
> new or new [], with deep copy I mean exact copy (or even the 
> temporary itself ...).

What are automatic members? Snipping the rest since it 
discusses more of making constructors to aggregate.

[toc] | [prev] | [next] | [standalone]


#67049

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 01:18 +0200
Message-ID<qgj1kg$h7s$1@dont-email.me>
In reply to#67048
On 16/07/19 00:40, Öö Tiib wrote:
> On Tuesday, 16 July 2019 01:01:03 UTC+3, Soviet_Mario  wrote:
>> I've been a long time far from C++ and I realize I have
>> forgotten most, and moreover don't understand "modern" C++
>> .... anyway
>>
>> When in a function (member or not is irrelevant) I build an
>> aggregate object (class / struct, possibly nested with
>> other), and this aggregate has a DEFAULT public constructor
>> which does not resort to new or new [], but then the said
>> former function invokes some class methods that DO some
>> dynamic allocation, and then the function returns passing
>> outside a copy by-value of the built object to the caller,
>> placed "partially" on the stack, the final copy will be
>> shallow or deep ?
> 
> Long sentence that sounded too controversial to

sorry for my tangled english :\

> understand. 1) An aggregate can't have ANY user-declared

I realize now I have mis-used this word (that had a precise 
meaning in C++!). So let replace it with "class/struct type 
object"

> constructors or destructors. 2) Returning objects of class
> type results with RVO (no copies made). 

could you explain this acronym ?

> 3) Your concept
> of shallow copies is also hard to understand:

only automatic (on stack) members, no "remote" (dynamic) 
data allocated with new / new []

> 
>> With shallow I mean : every automatic member not requiring
>> new or new [], with deep copy I mean exact copy (or even the
>> temporary itself ...).
> 
> What are automatic members?

the ones completely contained in the object itself.
I took the term automatic from "automatic" variables (with 
local scope, built on the stack) contrasted with "dynamic" 
variables (allocated manually from the heap and whose 
lifetime is to be manually managed too).


> Snipping the rest since it
> discusses more of making constructors to aggregate.

you are right, I mis-used the term !
I just meant some object containing both some automatic 
members and also some dynamically allocated ones.
TY



-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67050

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-07-15 21:12 -0400
Message-ID<qgj89q$dr3$1@dont-email.me>
In reply to#67049
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:
...
>> constructors or destructors. 2) Returning objects of class type 
>> results with RVO (no copies made).
> 
> could you explain this acronym ?

"... the return statement initializes the glvalue result or prvalue
result object of the (explicit or implicit) function call by
copy-initialization (11.6) from the operand. [ Note: A return statement
can involve an invocation of a constructor to perform a copy or move of
the operand if it is not a prvalue or if its type differs from the return
type of the function. A copy operation associated with a return
statement may be elided or converted to a move operation if an automatic
storage duration variable is returned." (9.6.3p2)

RVO is abbreviation for "Return Value Optimization", and refers to cases
in which a call to a copy constructor could in principle occur, but may
be elided.

That clause uses a couple of terms that you might not be familiar with:

"A glvalue is an expression whose evaluation determines the identity of
an object, bit-field, or function.
A prvalue is an expression whose evaluation initializes an object or a
bit-field, or computes the value of the operand of an operator, as
specified by the context in which it appears." (6.10p1).

>> 3) Your concept of shallow copies is also hard to understand:
> 
> only automatic (on stack) members, no "remote" (dynamic) data 
> allocated with new / new []>
>> 
>>> With shallow I mean : every automatic member not requiring new or
>>> new [], with deep copy I mean exact copy (or even the temporary
>>> itself ...).
>> 
>> What are automatic members?
> 
> the ones completely contained in the object itself. I took the term 
> automatic from "automatic" variables (with local scope, built on the
>  stack) contrasted with "dynamic" variables (allocated manually from
>  the heap and whose lifetime is to be manually managed too).

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.

>> Snipping the rest since it discusses more of making constructors to
>> aggregate.
> 
> you are right, I mis-used the term ! I just meant some object 
> containing both some automatic members and also some dynamically 
> allocated ones. TY

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 suspect that what you mean is members that are pointers to dynamically
allocated memory. Pointers are not distinguished by the storage duration
of the objects that they point at, any pointer can point at any suitable
object, regardless of that object's storage duration. Therefore, it's
not appropriate for the compiler to automatically free the memory a
pointer points at. It is the responsibility of the programmer, to make
sure that the memory it points at is in fact deallocated, when
appropriate, 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.

[toc] | [prev] | [next] | [standalone]


#67059

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 14:28 +0200
Message-ID<qgkft8$c20$1@dont-email.me>
In reply to#67050
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:
> ...
>>> constructors or destructors. 2) Returning objects of class type
>>> results with RVO (no copies made).
>>
>> could you explain this acronym ?
> 
> "... the return statement initializes the glvalue result or prvalue
> result object of the (explicit or implicit) function call by
> copy-initialization (11.6) from the operand. [ Note: A return statement
> can involve an invocation of a constructor to perform a copy or move of
> the operand if it is not a prvalue or if its type differs from the return
> type of the function. A copy operation associated with a return
> statement may be elided or converted to a move operation if an automatic
> storage duration variable is returned." (9.6.3p2)
> 
> RVO is abbreviation for "Return Value Optimization", and refers to cases
> in which a call to a copy constructor could in principle occur, but may
> be elided.
> 
> That clause uses a couple of terms that you might not be familiar with:
> 
> "A glvalue is an expression whose evaluation determines the identity of
> an object, bit-field, or function.
> A prvalue is an expression whose evaluation initializes an object or a
> bit-field, or computes the value of the operand of an operator, as
> specified by the context in which it appears." (6.10p1).
> 
>>> 3) Your concept of shallow copies is also hard to understand:
>>
>> only automatic (on stack) members, no "remote" (dynamic) data
>> allocated with new / new []>
>>>
>>>> With shallow I mean : every automatic member not requiring new or
>>>> new [], with deep copy I mean exact copy (or even the temporary
>>>> itself ...).
>>>
>>> What are automatic members?
>>
>> the ones completely contained in the object itself. I took the term
>> automatic from "automatic" variables (with local scope, built on the
>>   stack) contrasted with "dynamic" variables (allocated manually from
>>   the heap and whose lifetime is to be manually managed too).
> 
> 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

> 
>>> Snipping the rest since it discusses more of making constructors to
>>> aggregate.
>>
>> you are right, I mis-used the term ! I just meant some object
>> containing both some automatic members and also some dynamically
>> allocated ones. TY
> 
> 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, 
existing even for "empty" MyStrings, and some dynamic 
content (created and destroyed using new char [] / delege []

an empty MyString can be built without calling any new char 
[] / delege [], but further elaboration, which assigns 
content, requires it, or even reallocation.

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

> 
> I suspect that what you mean is members that are pointers to dynamically
> allocated memory.

exactly : some "rich" strings, that have a constant 
framework of members and an "optional" content, on the HEAP, 
pointed to by an automatic pointer member

> Pointers are not distinguished by the storage duration

yes I know pointers are not, but I have doubts for the 
actual content pointed to.

Avoiding DEEP copying (just copying the pointer, and thus 
having more than one pointer targeting the same content, 
would be destructive, as each MyString must have is private 
and locale space reserved, and modifying it must not affect 
others)

> 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) ? Is NEVER duplicated ? 
(harmful). Is the whole regulated by invoking the 
COPY-constructor, so that it can decide ?

> 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)
2) receive a link to the same content, copied in another pointer
3) receive a copy of the dynamic data placed elsewhere 
(which seems not reasonable if it was up to the compiler to 
reallocate some room, transfer the data, deallocate the 
CALLEE copy, but maybe this would be done if a COPY 
constructor is delegated, and this always makes a copy ... 
well this scenario seems heavy and inefficient, it would be 
good to just copy automatic members so that just one 
reference to data would exist after return, the one of the 
caller)

> 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)

> 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.
And C++ has changed very very much in 10-15 years I had 
almost abandoned it :\

> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67064

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-07-16 09:47 -0400
Message-ID<qgkkif$75t$1@dont-email.me>
In reply to#67059
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.

[toc] | [prev] | [next] | [standalone]


#67067

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 17:16 +0200
Message-ID<qgkpou$6h2$1@dont-email.me>
In reply to#67064
On 16/07/19 15:47, James Kuyper wrote:
> 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>

Thanks, I'm gonna get the DOC !

> 
> ...
>>> 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". 

mmm, the fact is : to me non-static seems a WIDER definition 
than automatic, as dynamic also 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.

uhm .... :\

> 
> If that member is a pointer to dynamically allocated memory, then *data
> has dynamic storage duration, regardless of what storage duration data
> itself has.

this IS clear !

> 
> ...
>> 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.

OK ... no problem, maybe I won't need to refine too :)

> 
> ...
>>> 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.

OK : I have written the copy-constructor, yes

> 
>> (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

yes...no ! No, I don't want COW even if it is faster and 
maybe more parsimonious. I just need code safer and simpler 
to read.

> 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. 

yes it's like the SNAPSHOTS on virtual machine disks : they 
actually record only the changes of status, not the entire 
status of the file system. Also BTRFS snapshots work like that.

I'd prefer more "synced" status of each object than deferred 
writes

> 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.

agreed. I had not even thought about such more advanced 
features as I just need to have simple and solid code : it 
won't be performance intensive

> 
> 
>>> 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.

OK clear: I should not expect strange hidden behaviour.

I'm getting maybe close to some compilable code .... then 
I'll inspect all in the Debugger. Some times is more useful 
to observe live than to try to figure out theoretically

> 
> ...
>>> 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.

mmm ... unheard of .... thanks for the hint !

> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67068

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-07-16 10:30 -0700
Message-ID<39ef7c7f-0fa2-47ae-9daf-898f7772bc3e@googlegroups.com>
In reply to#67067
On Tuesday, July 16, 2019 at 11:16:57 AM UTC-4, Soviet_Mario wrote:
> On 16/07/19 15:47, James Kuyper wrote:
> > On 7/16/19 8:28 AM, Soviet_Mario wrote:
...
> >> 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". 
> 
> mmm, the fact is : to me non-static seems a WIDER definition 
> than automatic, as dynamic also is non-static :)

Yes, it is wider. All members are either member functions, static data
members, non-static data members, nested classes, or typedef members.

The problem is that "automatic", as that term is defined by the
standard, doesn't describe a property of a class member - it describes a
property of a particular instance of a class, and that property applies
to all of the non-static data members of that instance. It's not
meaningful to talk about some of the members being automatic and others
being dynamic.

This isn't just pedantry - it's directly relevant to the issue you're
worrying about. Consider a class containing just two members: a pointer
to a dynamically allocated array and a count of the number of elements
in that array. I suspect that you would describe the count as
"automatic"; I'm not sure exactly what you would say about the pointer.
The relevant facts are that both the count and the pointer are
non-static data members. They both always have the same storage duration
- which is the storage duration of the object that they are part of. The
memory that the pointer points at is dynamically allocated - but that's
not a feature of the pointer member, it's a feature of the way that the
class code uses that pointer.

A default copy will copy both the value of the count and the value of
the pointer, and will not do anything special regarding the memory that
the pointer points at. If that's not what you want to have happen,
you'll have to write a constructor that actually does do what you want
to have happen.

[toc] | [prev] | [next] | [standalone]


#67069

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 19:44 +0200
Message-ID<qgl2eh$ue6$1@dont-email.me>
In reply to#67068
On 16/07/19 19:30, James Kuyper wrote:
> On Tuesday, July 16, 2019 at 11:16:57 AM UTC-4, Soviet_Mario wrote:
>> On 16/07/19 15:47, James Kuyper wrote:
>>> On 7/16/19 8:28 AM, Soviet_Mario wrote:
> ...
>>>> 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".
>>
>> mmm, the fact is : to me non-static seems a WIDER definition
>> than automatic, as dynamic also is non-static :)
> 
> Yes, it is wider. All members are either member functions, static data
> members, non-static data members, nested classes, or typedef members.
> 
> The problem is that "automatic", as that term is defined by the
> standard, doesn't describe a property of a class member - it describes a
> property of a particular instance of a class, and that property applies
> to all of the non-static data members of that instance. It's not
> meaningful to talk about some of the members being automatic and others
> being dynamic.
> 
> This isn't just pedantry -

oh, friend, never said or even thought so !!
I am just old-fashioned minded, an era when autopointers or 
worse AUTO determination of the return value by its context 
was really far fetched. So I was just trying to justify 
myself, my way of thinking.

> it's directly relevant to the issue you're
> worrying about. Consider a class containing just two members: a pointer
> to a dynamically allocated array and a count of the number of elements
> in that array. I suspect that you would describe the count as
> "automatic"; 

both the members are automatic. The pointer also IS. The 
buffer pointed to, on the contrary, I would not call it 
automatic, but dynamic.

> I'm not sure exactly what you would say about the pointer.

that in itself is automatic, as it still exist (it takes up 
4 or 8 byte even if it contains NULLPTR)

> The relevant facts are that both the count and the pointer are
> non-static data members. They both always have the same storage duration

I agree in fact

> - which is the storage duration of the object that they are part of. The
> memory that the pointer points at is dynamically allocated - but that's
> not a feature of the pointer member, 

yes it's not an intrinsical property of it, but this is not 
really important for the passing out mechanism

> it's a feature of the way that the
> class code uses that pointer.

yes, now I have understood that I can rely on the fact that 
the compiler itself generates no hidden code having side 
effects on dynamic data, except for calling copy-constructor 
and destructor, which I have to write myself.

And also that I cannot make assumptions whether or not the 
copy constructor is actually called or some optimization 
(like building the returned object in a location provided by 
the CALLER itself, or copying it back by MY copy-ctor) 
eliding copy happens.

> 
> A default copy will copy both the value of the count and the value of
> the pointer, and will not do anything special regarding the memory that
> the pointer points at.

I have my hand written copy-ctor that copies data, so I 
should be sure no overlapping ownership could take place

> If that's not what you want to have happen,
> you'll have to write a constructor that actually does do what you want
> to have happen.
> 

yes. Many thanks to you and every one else. Some rust 
removed successfully :) :)
CIAO


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67148

FromRosario19 <Ros@invalid.invalid>
Date2019-07-23 09:28 +0200
Message-ID<3gddjedd4f3epst54kl6shca9qj71p89n6@4ax.com>
In reply to#67059
On Tue, 16 Jul 2019 14:28:23 +0200, Soviet_Mario wrote:

>I am referring to objects of a class derived from MyString, 
>that have some automatic and / or static data members, 
>existing even for "empty" MyStrings, and some dynamic 
>content (created and destroyed using new char [] / delege []
>
>an empty MyString can be built without calling any new char 
>[] / delege [], but further elaboration, which assigns 
>content, requires it, or even reallocation.
>
>So I was asking about the behaviou

in un debugger, puoi vedere le funzioni che vengono chiamate...
in generale ogni obj non tuo, ha propri costruttori e tutto va bene
no leak ecc

se ci sono object tuoi, che abbisognano memoria dinamica allora devi
stare attento... per quel che mi riguarda in qualche esercizio la cosa
che avrei fatto, per chiarire il fatto della memoria, è stato
(ri)costruire malloc free e new e vedere come la memoria veniva
utilizzata 
nei obj che avevo costruito, in particolare vedere se c'erano leak

[toc] | [prev] | [next] | [standalone]


#67053

FromÖö Tiib <ootiib@hot.ee>
Date2019-07-15 20:22 -0700
Message-ID<d2d4833c-f06b-4b49-bbee-3e9eab0ffec2@googlegroups.com>
In reply to#67049
On Tuesday, 16 July 2019 02:18:51 UTC+3, Soviet_Mario  wrote:
> On 16/07/19 00:40, Öö Tiib wrote:
> 
> > constructors or destructors. 2) Returning objects of class
> > type results with RVO (no copies made). 
> 
> could you explain this acronym ?

I see James Kuyper made decent effort to explain it.
In practice the implementations pass the address for
return value of class type to function like other arguments.
The function is allowed to construct the object that it is going
to return at that address and so elide copying when returning.
It often surprises people who wrote side effects to copy or
move constructors or destructors. 

> > 3) Your concept
> > of shallow copies is also hard to understand:
> 
> only automatic (on stack) members, no "remote" (dynamic) 
> data allocated with new / new []
> 
> > 
> >> With shallow I mean : every automatic member not requiring
> >> new or new [], with deep copy I mean exact copy (or even the
> >> temporary itself ...).
> > 
> > What are automatic members?
> 
> the ones completely contained in the object itself.
> I took the term automatic from "automatic" variables (with 
> local scope, built on the stack) contrasted with "dynamic" 
> variables (allocated manually from the heap and whose 
> lifetime is to be manually managed too).

Hmm.

Making efficient manual management of resources with C++ 
has become quite complicated topic.
It can take more than week to read and to understand the 
nuances of "RAII", "rule of three", "copy-swap idiom", 
"rule of five", "rule of zero" and "rule of four (and half)".

People who write about one of those tend to oversimplify the issue.
For example they typically forget to tell that with dynamically
polymorphic class hierarchy (with virtual functions) all exposed
copying, moving or swapping may cause sliced objects or worse.
So protect or =delete all that and use factories and cloning
with such hierarchies instead.

[toc] | [prev] | [next] | [standalone]


#67060

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 14:37 +0200
Message-ID<qgkge2$f5c$1@dont-email.me>
In reply to#67053
On 16/07/19 05:22, Öö Tiib wrote:
> On Tuesday, 16 July 2019 02:18:51 UTC+3, Soviet_Mario  wrote:
>> On 16/07/19 00:40, Öö Tiib wrote:
>>
>>> constructors or destructors. 2) Returning objects of class
>>> type results with RVO (no copies made).
>>
>> could you explain this acronym ?
> 
> I see James Kuyper made decent effort to explain it.

sure, he was kind. I just have to collect a copy of the 
document he was referring to

> In practice the implementations pass the address for
> return value of class type to function like other arguments.

do you mean the CALLER passes an "hidden" further parameter 
to the CALLEE indicating where to place the (automatic part 
of the) built object ?
In this case, the inefficient COPY-constructor would not be 
invoked ...

> The function is allowed to construct the object that it is going
> to return at that address and so elide copying when returning.

intresting ... I knew nothing about this mechanism

> It often surprises people who wrote side effects to copy or
> move constructors or destructors.

I could not understand what you meant ...
I had to add the copy constructor to just clone-initialize 
objects explicitly.
I thought (wrongly) it would have been invoked also in 
returning objects on the stack. But if this does not happen, 
much better !

> 
>>> 3) Your concept
>>> of shallow copies is also hard to understand:
>>
>> only automatic (on stack) members, no "remote" (dynamic)
>> data allocated with new / new []
>>
>>>
>>>> With shallow I mean : every automatic member not requiring
>>>> new or new [], with deep copy I mean exact copy (or even the
>>>> temporary itself ...).
>>>
>>> What are automatic members?
>>
>> the ones completely contained in the object itself.
>> I took the term automatic from "automatic" variables (with
>> local scope, built on the stack) contrasted with "dynamic"
>> variables (allocated manually from the heap and whose
>> lifetime is to be manually managed too).
> 
> Hmm.
> 
> Making efficient manual management of resources with C++
> has become quite complicated topic.

I was afraid so, but I have to do some MyString class, and 
there the dynamic management is unavoidable I fear

> It can take more than week to read and to understand the
> nuances of "RAII", "rule of three", "copy-swap idiom",
> "rule of five", "rule of zero" and "rule of four (and half)".

I had just read about resource acquisition is 
initialization. Never heard of the other bibl.

> 
> People who write about one of those tend to oversimplify the issue.
> For example they typically forget to tell that with dynamically
> polymorphic class hierarchy (with virtual functions) all exposed
> copying, moving or swapping may cause sliced objects or worse.
> So protect or =delete all that and use factories and cloning
> with such hierarchies instead.


I am still not using virtual classes/members.
And not even inheritance of the kind IS-A (I tend to use the 
HAS-A pattern, which I'm more confident of)


actually I'm using C++ more like "a better C" and little 
more, or C-with-templates.

> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67081

FromÖö Tiib <ootiib@hot.ee>
Date2019-07-17 01:41 -0700
Message-ID<ffa24f68-eda3-42f0-860b-2544eb158648@googlegroups.com>
In reply to#67060
On Tuesday, 16 July 2019 15:37:32 UTC+3, Soviet_Mario  wrote:
> On 16/07/19 05:22, Öö Tiib wrote:
> 
> > In practice the implementations pass the address for
> > return value of class type to function like other arguments.
> 
> do you mean the CALLER passes an "hidden" further parameter 
> to the CALLEE indicating where to place the (automatic part 
> of the) built object ?
> In this case, the inefficient COPY-constructor would not be 
> invoked ...

Yes, there is hidden parameter pointing at
uninitialized memory.

> > The function is allowed to construct the object that it is going
> > to return at that address and so elide copying when returning.
> 
> intresting ... I knew nothing about this mechanism

Also where copy elision is allowed but compiler does not find a
way to elide copy there it is typically required to move if 
move constructors are available. Read that too, it is less
formal and accurate but bit easier to read than standard:
https://en.cppreference.com/w/cpp/language/copy_elision

> 
> > It often surprises people who wrote side effects to copy or
> > move constructors or destructors.
> 
> I could not understand what you meant ...
> I had to add the copy constructor to just clone-initialize 
> objects explicitly.
> I thought (wrongly) it would have been invoked also in 
> returning objects on the stack. But if this does not happen, 
> much better !

I meant that people sometimes add side effects to their
copy/move constructors and destructors. For example output to some
log. Then are surprised to not see the log entries they expected.

> > 
> >>> 3) Your concept
> >>> of shallow copies is also hard to understand:
> >>
> >> only automatic (on stack) members, no "remote" (dynamic)
> >> data allocated with new / new []
> >>
> >>>
> >>>> With shallow I mean : every automatic member not requiring
> >>>> new or new [], with deep copy I mean exact copy (or even the
> >>>> temporary itself ...).
> >>>
> >>> What are automatic members?
> >>
> >> the ones completely contained in the object itself.
> >> I took the term automatic from "automatic" variables (with
> >> local scope, built on the stack) contrasted with "dynamic"
> >> variables (allocated manually from the heap and whose
> >> lifetime is to be manually managed too).
> > 
> > Hmm.
> > 
> > Making efficient manual management of resources with C++
> > has become quite complicated topic.
> 
> I was afraid so, but I have to do some MyString class, and 
> there the dynamic management is unavoidable I fear

Usual advice is to use standard library classes (like std::string)
as data members (or sometimes as private bases) of your class. 
These do memory management for you and so you have to write only
the special functionality of your MyString.

> > It can take more than week to read and to understand the
> > nuances of "RAII", "rule of three", "copy-swap idiom",
> > "rule of five", "rule of zero" and "rule of four (and half)".
> 
> I had just read about resource acquisition is 
> initialization. Never heard of the other bibl.

For historic reasons the C++ compiler generates some public
code for classes implicitly (if it can). That code can be correct
or incorrect depending on logic of class and so people have made
rules how to ensure that it does not cause any issues.

> > People who write about one of those tend to oversimplify the issue.
> > For example they typically forget to tell that with dynamically
> > polymorphic class hierarchy (with virtual functions) all exposed
> > copying, moving or swapping may cause sliced objects or worse.
> > So protect or =delete all that and use factories and cloning
> > with such hierarchies instead.
> 
> 
> I am still not using virtual classes/members.
> And not even inheritance of the kind IS-A (I tend to use the 
> HAS-A pattern, which I'm more confident of)
> 
> 
> actually I'm using C++ more like "a better C" and little 
> more, or C-with-templates.

When you work alone then it is fine, but success is easier to achieve
when using code written by others and so cooperating with others.

[toc] | [prev] | [next] | [standalone]


#67058

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2019-07-16 15:04 +0300
Message-ID<qgkego$4q8$1@dont-email.me>
In reply to#67046
On 16.07.2019 1:00, Soviet_Mario wrote:
>
> I've been a long time far from C++ and I realize I have forgotten most,
> and moreover don't understand "modern" C++ .... anyway
>
> When in a function (member or not is irrelevant) I build an aggregate
> object (class / struct, possibly nested with other), and this aggregate
> has a DEFAULT public constructor which does not resort to new or new [],
> but then the said former function invokes some class methods that DO
> some dynamic allocation, and then the function returns passing outside a
> copy by-value of the built object to the caller, placed "partially" on

Your question is not very clear, consider to add some code examples to 
make it clearer.

In general, defining classes which do their own own low-level dynamic 
memory allocation is tricky. One typically needs to define custom 
constructors, assignments and destructors.

Fortunately enough, there is near zero need to do such low-level dynamic 
allocation nowadays in C++, as it's properly done and encapsulated in 
standard library classes like std::vector. If some objects really need 
to be dynamically allocated, like some OOP hierarchy objects, one should 
use std::make_unique() (or maybe std::make_shared() in special 
circumstances) and appropriate smartpointers.

That said, the answer to your question is probably that by default the 
copies in C++ are "shallow" (a copy of a pointer or a standard 
smartpointer is just another pointer with the same value), to make it 
deep one needs to define custom copy and assignment operations. The 
latter is done e.g. by std::vector, so copying std::vector objects 
always copies the whole data array.

hth
Paavo

[toc] | [prev] | [next] | [standalone]


#67061

FromSoviet_Mario <SovietMario@CCCP.MIR>
Date2019-07-16 14:42 +0200
Message-ID<qgkgn4$gko$1@dont-email.me>
In reply to#67058
On 16/07/19 14:04, Paavo Helde wrote:
> On 16.07.2019 1:00, Soviet_Mario wrote:
>>
>> I've been a long time far from C++ and I realize I have 
>> forgotten most,
>> and moreover don't understand "modern" C++ .... anyway
>>
>> When in a function (member or not is irrelevant) I build 
>> an aggregate
>> object (class / struct, possibly nested with other), and 
>> this aggregate
>> has a DEFAULT public constructor which does not resort to 
>> new or new [],
>> but then the said former function invokes some class 
>> methods that DO
>> some dynamic allocation, and then the function returns 
>> passing outside a
>> copy by-value of the built object to the caller, placed 
>> "partially" on
> 
> Your question is not very clear, consider to add some code 
> examples to make it clearer.
> 
> In general, defining classes which do their own own 
> low-level dynamic memory allocation is tricky. One typically 
> needs to define custom constructors, assignments and 
> destructors.
> 
> Fortunately enough, there is near zero need to do such 
> low-level dynamic allocation nowadays in C++, as it's 
> properly done and encapsulated in standard library classes 
> like std::vector.

It was my first attempt : std::vector and std::list, but I 
was unable to find the methods to do both dynamic 
reallocation (grow / shrink) with the former and also random 
access BY INDEX with the latter.

> If some objects really need to be 
> dynamically allocated, like some OOP hierarchy objects, one 
> should use std::make_unique() (or maybe std::make_shared() 
> in special circumstances) and appropriate smartpointers.
> 
> That said, the answer to your question is probably that by 
> default the copies in C++ are "shallow" (a copy of a pointer 
> or a standard smartpointer is just another pointer with the 
> same value), to make it deep one needs to define custom copy 
> and assignment operations. 

I have defined both, it seemed inevitable with read-write 
Strings

> The latter is done e.g. by 
> std::vector, so copying std::vector objects always copies 
> the whole data array.

I'll rescan the std:: types you adviced though :\
TY

> 
> hth
> Paavo
> 


-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

[toc] | [prev] | [next] | [standalone]


#67063

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2019-07-16 16:15 +0300
Message-ID<qgkime$sfm$1@dont-email.me>
In reply to#67061
On 16.07.2019 15:42, Soviet_Mario wrote:
> On 16/07/19 14:04, Paavo Helde wrote:
>> On 16.07.2019 1:00, Soviet_Mario wrote:
>>>
>>> I've been a long time far from C++ and I realize I have forgotten most,
>>> and moreover don't understand "modern" C++ .... anyway
>>>
>>> When in a function (member or not is irrelevant) I build an aggregate
>>> object (class / struct, possibly nested with other), and this aggregate
>>> has a DEFAULT public constructor which does not resort to new or new [],
>>> but then the said former function invokes some class methods that DO
>>> some dynamic allocation, and then the function returns passing outside a
>>> copy by-value of the built object to the caller, placed "partially" on
>>
>> Your question is not very clear, consider to add some code examples to
>> make it clearer.
>>
>> In general, defining classes which do their own own low-level dynamic
>> memory allocation is tricky. One typically needs to define custom
>> constructors, assignments and destructors.
>>
>> Fortunately enough, there is near zero need to do such low-level
>> dynamic allocation nowadays in C++, as it's properly done and
>> encapsulated in standard library classes like std::vector.
>
> It was my first attempt : std::vector and std::list, but I was unable to
> find the methods to do both dynamic reallocation (grow / shrink) with
> the former and also random access BY INDEX with the latter.

std::vector is perfectly capable to dynamically grow and shrink. Insert 
and erase elsewhere than in the end might be a bit slow if you have 
millions of elements, but one should not worry about it prematurely.

[toc] | [prev] | [next] | [standalone]


#67065

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-07-16 10:07 -0400
Message-ID<qgklmb$duu$1@dont-email.me>
In reply to#67061
On 7/16/19 8:42 AM, Soviet_Mario wrote:
...
> It was my first attempt : std::vector and std::list, but I 
> was unable to find the methods to do both dynamic 
> reallocation (grow / shrink)

The relevant methods are various overloads to insert() and erase(), as
well as push_back() and pop_back(). If you simply want to expand the
allocated memory without filling it immediately, use reserve(). If you
want to shed unneeded allocated memory, use shrink_to_fit().

> with the former and also random 
> access BY INDEX with the latter.

By it's vary nature std::list cannot support  random access. If you need
random access, you shouldn't be using a list.

If you absolutely need use an index, std::next(list.begin(), n) will
return an iterator referring to the n'th element of the list. This isn't
true random access: it applies operator++() to the iterator n times, in
order to get to that location.

[toc] | [prev] | [next] | [standalone]


#67079

FromJuha Nieminen <nospam@thanks.invalid>
Date2019-07-17 07:36 +0000
Message-ID<qgmj6b$2ea1$1@adenine.netfront.net>
In reply to#67046
Soviet_Mario <SovietMario@cccp.mir> wrote:
> When in a function (member or not is irrelevant) I build an 
> aggregate object (class / struct, possibly nested with 
> other), and this aggregate has a DEFAULT public constructor 
> which does not resort to new or new [], but then the said 
> former function invokes some class methods that DO some 
> dynamic allocation, and then the function returns passing 
> outside a copy by-value of the built object to the caller, 
> placed "partially" on the stack, the final copy will be 
> shallow or deep ?

It's up that type returned by that function how it behaves
when copied. For example, if the returned type is std::vector,
copying it will make a deep copy (although in this case that
will most probably be skipped because of return value optimization).
If the returned type is std::shared_ptr, copying it will,
essentially, be a shallow copy (the managed object will not
be copied; all std::shared_ptr instances copied from the
original will share the same managed object).

If it's your own type, your own class, that's being returned,
then it's up to you how it behaves when copied.

The first part of your question is completely unrelated to this
and I don't really understand why you think it's relevant. It
doesn't matter *where* that function is called from.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web