Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

shared_ptr array range loop doesn't work

131 views
Skip to first unread message

Mut...@dastardlyhq.com

unread,
May 18, 2023, 5:10:57 AM5/18/23
to
Is there a way to get range loops to work with arrays stored in
shared pointers?

eg:

#include <iostream>
#include <memory>

using namespace std;

struct mystruct
{
mystruct() { cout << "Con " << this << endl; };
~mystruct() { cout << "Dest " << this << endl; }
void func() { cout << "Func " << this << endl; }
};


int main()
{
shared_ptr<mystruct[3]> sp(new mystruct[3]);
sp[0].func();
sp[1].func();
sp[2].func();
for(auto &ms: sp.get()) ms.func(); <--- Doesn't compile
return 0;
}

I've tried other combinations too, nothing works.

Chris M. Thomasson

unread,
May 18, 2023, 5:27:08 AM5/18/23
to
On 5/18/2023 2:10 AM, Mut...@dastardlyhq.com wrote:
> Is there a way to get range loops to work with arrays stored in
> shared pointers?
>
> eg:
>
> #include <iostream>
> #include <memory>
>
> using namespace std;
>
> struct mystruct
> {
> mystruct() { cout << "Con " << this << endl; };
> ~mystruct() { cout << "Dest " << this << endl; }
> void func() { cout << "Func " << this << endl; }
> };
>
>
> int main()
> {
> shared_ptr<mystruct[3]> sp(new mystruct[3]);

Seems a bit odd:

std::vector<std::shared_ptr<mystruct>> vec(3)?

Bonita Montero

unread,
May 18, 2023, 8:24:39 AM5/18/23
to
Use this:

#include <iostream>
#include <memory>
#include <array>

using namespace std;

struct mystruct
{
mystruct() { cout << "Con " << this << endl; };
~mystruct() { cout << "Dest " << this << endl; }
void func() { cout << "Func " << this << endl; }
};


int main()
{
using arr3_t = array<mystruct, 3>;
shared_ptr<arr3_t> sp( make_shared<arr3_t>() );
(*sp)[0].func();
(*sp)[1].func();
(*sp)[2].func();
for( auto &ms : *sp.get() )
ms.func();
return 0;
}

Mut...@dastardlyhq.com

unread,
May 18, 2023, 11:06:01 AM5/18/23
to
On Thu, 18 May 2023 02:24:51 -0700
"Chris M. Thomasson" <chris.m.t...@gmail.com> wrote:
>On 5/18/2023 2:10 AM, Mut...@dastardlyhq.com wrote:
>> Is there a way to get range loops to work with arrays stored in
>> shared pointers?
>>
>> eg:
>>
>> #include <iostream>
>> #include <memory>
>>
>> using namespace std;
>>
>> struct mystruct
>> {
>> mystruct() { cout << "Con " << this << endl; };
>> ~mystruct() { cout << "Dest " << this << endl; }
>> void func() { cout << "Func " << this << endl; }
>> };
>>
>>
>> int main()
>> {
>> shared_ptr<mystruct[3]> sp(new mystruct[3]);
>
>Seems a bit odd:
>

Its new with C++ 2017 apparently. I didn't know about this functionality either
until I watched this youtube video:

https://www.youtube.com/watch?v=Tp5-f9YAzNk

Mut...@dastardlyhq.com

unread,
May 18, 2023, 11:08:50 AM5/18/23
to
On Thu, 18 May 2023 14:22:57 +0200
Bonita Montero <Bonita....@gmail.com> wrote:
>Use this:

I wasn't looking for an alternative solution, there are many. I was just
wondering if its possible to iterate the C array stored in a shared pointer.

Alf P. Steinbach

unread,
May 18, 2023, 11:35:23 AM5/18/23
to
On 2023-05-18 11:10 AM, Mut...@dastardlyhq.com wrote:
> #include <iostream>
> #include <memory>
>
> using namespace std;
>
> struct mystruct
> {
> mystruct() { cout << "Con " << this << endl; };
> ~mystruct() { cout << "Dest " << this << endl; }
> void func() { cout << "Func " << this << endl; }
> };
>
>
> int main()
> {
> shared_ptr<mystruct[3]> sp(new mystruct[3]);
> sp[0].func();
> sp[1].func();
> sp[2].func();
> for(auto &ms: sp.get()) ms.func(); <--- Doesn't compile
> return 0;
> }

Like this:


#include <iostream>
#include <memory>
using namespace std;

//--------------------------------------- Support machinery:
template< class It >
class Its_range_
{
It m_start;
It m_beyond;

public:
Its_range_( const It start, const It beyond ):
m_start( start ),
m_beyond( beyond )
{}

auto begin() const -> It { return m_start; }
auto end() const -> It { return m_beyond; }
};

template< class Item, int n >
auto its_const_range( const shared_ptr<Item[n]> sp )
-> Its_range_<const Item*>
{ return {sp.get(), sp.get() + n}; }


//--------------------------------------- Example:

struct My_struct
{
My_struct() { cout << "Con " << this << endl; };
~My_struct() { cout << "Dest " << this << endl; }
void func() const { cout << "Func " << this << endl; }
};

auto main() -> int
{
shared_ptr<My_struct[3]> sp( new My_struct[3] );
for( auto& ms: its_const_range( sp ) ) {
ms.func();
}
}


- Alf

Mut...@dastardlyhq.com

unread,
May 18, 2023, 11:50:46 AM5/18/23
to
On Thu, 18 May 2023 17:33:53 +0200
"Alf P. Steinbach" <alf.p.s...@gmail.com> wrote:
> for( auto& ms: its_const_range( sp ) ) {
> ms.func();
> }

Well yes, it works, but I was rather hoping that there was a built in way
to do it! Seems like this functionality is rather half baked - you can store
an array in shared_ptr but you can't iterate it directly in a range loop.
Might as well just use a vector.

Bonita Montero

unread,
May 18, 2023, 11:57:52 AM5/18/23
to
Am 18.05.2023 um 17:50 schrieb Mut...@dastardlyhq.com:

> Well yes, it works, but I was rather hoping that there was a built in way
> to do it! Seems like this functionality is rather half baked - you can store
> an array in shared_ptr but you can't iterate it directly in a range loop.
> Might as well just use a vector.

I don't understand why you won't use a std:array<>. I prefer that over
a C-style array because I get bounds-checking for free while debugging.



Mut...@dastardlyhq.com

unread,
May 18, 2023, 12:03:08 PM5/18/23
to
Its some new functionality I learnt about, was just seeing if it was useful.
Seems not. I would never use it myself anyway, plenty of better alternatives.

Chris M. Thomasson

unread,
May 18, 2023, 4:22:06 PM5/18/23
to
On 5/18/2023 8:05 AM, Mut...@dastardlyhq.com wrote:
> On Thu, 18 May 2023 02:24:51 -0700
> "Chris M. Thomasson" <chris.m.t...@gmail.com> wrote:
>> On 5/18/2023 2:10 AM, Mut...@dastardlyhq.com wrote:
>>> Is there a way to get range loops to work with arrays stored in
>>> shared pointers?
>>>
>>> eg:
>>>
>>> #include <iostream>
>>> #include <memory>
>>>
>>> using namespace std;
>>>
>>> struct mystruct
>>> {
>>> mystruct() { cout << "Con " << this << endl; };
>>> ~mystruct() { cout << "Dest " << this << endl; }
>>> void func() { cout << "Func " << this << endl; }
>>> };
>>>
>>>
>>> int main()
>>> {
>>> shared_ptr<mystruct[3]> sp(new mystruct[3]);
[...]

struct xxx
{
mystruct m_x[3];
};

std::shared_ptr<xxx> Well, what about that fing shit? ;^)

Pavel

unread,
May 19, 2023, 11:19:56 PM5/19/23
to
Mut...@dastardlyhq.com wrote:
> Is there a way to get range loops to work with arrays stored in
> shared pointers?
These shared pointers do not store arrays. They store pointers to memory
object allocated with operator new[].

In other words, the type shared_ptr<mystruct[3]>::element_type is same
as shared_ptr<mystruct>::element_type i.e. mystruct.

To get a feeling of why it's natural, note that the type of the
expression "new mystruct[3]" that you use to initalize sp is mystruct*,
not mystruct (*)[3].

Therefore, it is not possible to iterate the way you want: there is no
either constexpr 3 anywhere in the type of shared_ptr<mystruct[3]> or
non-constexpr 3 that could be extracted from the object in memory in any
implementation-independent way. Thus, there is no way for C++ compiler
to generate the code that would compute the end of the range.

>
> eg:
>
> #include <iostream>
> #include <memory>
>
> using namespace std;
>
> struct mystruct
> {
> mystruct() { cout << "Con " << this << endl; };
> ~mystruct() { cout << "Dest " << this << endl; }
> void func() { cout << "Func " << this << endl; }
> };
>
>
> int main()
> {
> shared_ptr<mystruct[3]> sp(new mystruct[3]);
> sp[0].func();
> sp[1].func();
> sp[2].func();
> for(auto &ms: sp.get()) ms.func(); <--- Doesn't compile
> return 0;
> }
>
> I've tried other combinations too, nothing works.
>

HTH
-Pavel

Mut...@dastardlyhq.com

unread,
May 20, 2023, 4:58:53 AM5/20/23
to
On Fri, 19 May 2023 23:19:30 -0400
Pavel <pauldont...@removeyourself.dontspam.yahoo> wrote:
>Mut...@dastardlyhq.com wrote:
>> Is there a way to get range loops to work with arrays stored in
>> shared pointers?
>These shared pointers do not store arrays. They store pointers to memory
>object allocated with operator new[].
>
>In other words, the type shared_ptr<mystruct[3]>::element_type is same
>as shared_ptr<mystruct>::element_type i.e. mystruct.
>
>To get a feeling of why it's natural, note that the type of the
>expression "new mystruct[3]" that you use to initalize sp is mystruct*,
>not mystruct (*)[3].

Fair enough. Does make me wonder why they bothered to introduce this
particular semantic for shared pointers.

Chris M. Thomasson

unread,
May 20, 2023, 5:39:57 PM5/20/23
to
On 5/20/2023 2:38 PM, Alf P. Steinbach wrote:
> On 2023-05-20 5:19 AM, Pavel wrote:
>> Mut...@dastardlyhq.com wrote:
>>> Is there a way to get range loops to work with arrays stored in
>>> shared pointers?
>> These shared pointers do not store arrays. They store pointers to
>> memory object allocated with operator new[].
>>
>> In other words, the type shared_ptr<mystruct[3]>::element_type is same
>> as shared_ptr<mystruct>::element_type i.e. mystruct.
>>
>> To get a feeling of why it's natural, note that the type of the
>> expression "new mystruct[3]" that you use to initalize sp is
>> mystruct*, not mystruct (*)[3].
>>
>> Therefore, it is not possible to iterate the way you want: there is no
>> either constexpr 3 anywhere in the type of shared_ptr<mystruct[3]> or
>> non-constexpr 3 that could be extracted from the object in memory in
>> any implementation-independent way. Thus, there is no way for C++
>> compiler to generate the code that would compute the end of the range.
>
> Oh, there is such a way.
>
> `shared_ptr` currently makes available an indexing operator if the item
> type is array: <url:
> https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_at>.

Thanks! I did not know that.

>
> It could just as easily make available `begin` and `end` operations for
> array item type, and then a range based loop would Just Work. My earlier
> answer in this thread showed how to do that oneself. And what I can do
> (it was trivial enough that a dino could manage) the committee could do.


Alf P. Steinbach

unread,
May 20, 2023, 5:40:10 PM5/20/23
to
On 2023-05-20 5:19 AM, Pavel wrote:
> Mut...@dastardlyhq.com wrote:
>> Is there a way to get range loops to work with arrays stored in
>> shared pointers?
> These shared pointers do not store arrays. They store pointers to memory
> object allocated with operator new[].
>
> In other words, the type shared_ptr<mystruct[3]>::element_type is same
> as shared_ptr<mystruct>::element_type i.e. mystruct.
>
> To get a feeling of why it's natural, note that the type of the
> expression "new mystruct[3]" that you use to initalize sp is mystruct*,
> not mystruct (*)[3].
>
> Therefore, it is not possible to iterate the way you want: there is no
> either constexpr 3 anywhere in the type of shared_ptr<mystruct[3]> or
> non-constexpr 3 that could be extracted from the object in memory in any
> implementation-independent way. Thus, there is no way for C++ compiler
> to generate the code that would compute the end of the range.

Oh, there is such a way.

`shared_ptr` currently makes available an indexing operator if the item
type is array: <url:
https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_at>.

It could just as easily make available `begin` and `end` operations for
array item type, and then a range based loop would Just Work. My earlier
answer in this thread showed how to do that oneself. And what I can do
(it was trivial enough that a dino could manage) the committee could do.


- Alf

Pavel

unread,
May 20, 2023, 11:53:44 PM5/20/23
to
Alf P. Steinbach wrote:
> On 2023-05-20 5:19 AM, Pavel wrote:
>> Mut...@dastardlyhq.com wrote:
>>> Is there a way to get range loops to work with arrays stored in
>>> shared pointers?
>> These shared pointers do not store arrays. They store pointers to
>> memory object allocated with operator new[].
>>
>> In other words, the type shared_ptr<mystruct[3]>::element_type is same
>> as shared_ptr<mystruct>::element_type i.e. mystruct.
>>
>> To get a feeling of why it's natural, note that the type of the
>> expression "new mystruct[3]" that you use to initalize sp is
>> mystruct*, not mystruct (*)[3].
>>
>> Therefore, it is not possible to iterate the way you want: there is no
>> either constexpr 3 anywhere in the type of shared_ptr<mystruct[3]> or
>> non-constexpr 3 that could be extracted from the object in memory in
>> any implementation-independent way. Thus, there is no way for C++
>> compiler to generate the code that would compute the end of the range.
>
> Oh, there is such a way.
Not without changing the Standard. My understanding is that OP tried to
make his code iterate with the shared pointers *as they are currently
defined* in the Standard.

>
> `shared_ptr` currently makes available an indexing operator if the item
> type is array: <url:
> https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_at>.
>
> It could just as easily make available `begin` and `end` operations for
> array item type, and then a range based loop would Just Work. My earlier
> answer in this thread showed how to do that oneself. And what I can do
> (it was trivial enough that a dino could manage) the committee could do.
They could, for the template parameter of an array type U[N]. It is
unclear what is supposed to be done for the parameter of an array type U[].

But, with the current Standard, the N is lost. I am ok with this though
as adding this "feature" would open the whole new can of warms for
unclear benefit.

E.g. assume that, in line with your example, N becomes part of
shared_ptr instatiation *type* and consider this definition:

shared_ptr<mystruct[3]> sp(new mystruct[2]);

or, even better:

shared_ptr<mystruct[3]> sp(new mystruct[getNOfMyStructs()]);

What can possibly go wrong? (TM)

>
>
> - Alf
>

-Pavel

Mut...@dastardlyhq.com

unread,
May 22, 2023, 4:27:16 AM5/22/23
to
On Sat, 20 May 2023 23:53:18 -0400
Pavel <pauldont...@removeyourself.dontspam.yahoo> wrote:
>Alf P. Steinbach wrote:
>> It could just as easily make available `begin` and `end` operations for
>> array item type, and then a range based loop would Just Work. My earlier
>> answer in this thread showed how to do that oneself. And what I can do
>> (it was trivial enough that a dino could manage) the committee could do.
>They could, for the template parameter of an array type U[N]. It is
>unclear what is supposed to be done for the parameter of an array type U[].
>
>But, with the current Standard, the N is lost. I am ok with this though

N might be lost to the user but the compiler/runtime is quite well aware of
what it is otherwise delete[] couldn't work which makes me wonder why its
not made available to range based loops.


Mut...@dastardlyhq.com

unread,
May 22, 2023, 4:33:46 AM5/22/23
to
On Sat, 20 May 2023 14:39:39 -0700
"Chris M. Thomasson" <chris.m.t...@gmail.com> wrote:
>On 5/20/2023 2:38 PM, Alf P. Steinbach wrote:
>> Oh, there is such a way.
>>
>> `shared_ptr` currently makes available an indexing operator if the item
>> type is array: <url:
>> https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_at>.
>
>Thanks! I did not know that.

Neither did I until I watched the youtube video I linked to a few posts
back. Thats the problem with modern C++, the language is far too big for any
one person to know (probably even Bjarne). Whenever I come across something
new I write a little test program with come keywords in the comments so I
can just grep for them when I need similar functionality in the future because
I know I'm never going to remember all of them if I don't use them much.

Bonita Montero

unread,
May 22, 2023, 4:47:28 AM5/22/23
to
Am 22.05.2023 um 10:24 schrieb Mut...@dastardlyhq.com:

> N might be lost to the user but the compiler/runtime is quite well aware of
> what it is otherwise delete[] couldn't work which makes me wonder why its
> not made available to range based loops.

There are specializations for array'd shared_ptr-s / unique_ptr-s.


Mut...@dastardlyhq.com

unread,
May 22, 2023, 5:24:42 AM5/22/23
to
You missed the point. The compiler is well aware of how many elements are
in the array pointed to by a C pointer created by new[] so why not extend that
awareness to range based loops without any specialisations being required?

Fred. Zwarts

unread,
May 22, 2023, 5:54:01 AM5/22/23
to
Op 22.mei.2023 om 11:22 schreef Mut...@dastardlyhq.com:
That is difficult to specify in de standard, because it depends very
much on the context. Given a pointer in an arbitrary context how could
the compiler know that it was created by new[]? There is a reason that
there is a delete and a delete[], because the compiler does not always
know from a pointer alone how it was created, so the programmer has to
help the compiler. Only if the creation of the pointer with new[] is
visible by the compiler, then it could know use that information, but
that is not always the case.

Mut...@dastardlyhq.com

unread,
May 22, 2023, 6:13:52 AM5/22/23
to
Ok, so if the *ms pointer below has no attached metadata other than the raw
memory size allocated how does delete[] know to iterate through 3 elements?
Does it literally divide the memory allocation size by individual object size
and use that as the count? There's no reason that approach couldn't be used
in range based loops too.

using namespace std;

struct mystruct
{
mystruct() { cout << "Con " << this << endl; };
~mystruct() { cout << "Dest " << this << endl; }
};


int main()
{
mystruct *ms = new mystruct[3];
delete[] ms;
return 0;
}


Bonita Montero

unread,
May 22, 2023, 11:50:19 AM5/22/23
to
Because the shared_ptr would need a .begin(), .end() and further
things required for a loop. And C-style arrays are outdated in
favor of std::array<> anyway.

Mut...@dastardlyhq.com

unread,
May 22, 2023, 12:06:27 PM5/22/23
to
On Mon, 22 May 2023 17:48:34 +0200
Bonita Montero <Bonita....@gmail.com> wrote:
>Am 22.05.2023 um 11:22 schrieb Mut...@dastardlyhq.com:
>> On Mon, 22 May 2023 10:47:17 +0200
>> Bonita Montero <Bonita....@gmail.com> wrote:
>>> Am 22.05.2023 um 10:24 schrieb Mut...@dastardlyhq.com:
>>>
>>>> N might be lost to the user but the compiler/runtime is quite well aware of
>
>>>> what it is otherwise delete[] couldn't work which makes me wonder why its
>>>> not made available to range based loops.
>>>
>>> There are specializations for array'd shared_ptr-s / unique_ptr-s.
>>>
>>
>> You missed the point. The compiler is well aware of how many elements are
>> in the array pointed to by a C pointer created by new[] so why not extend
>that
>> awareness to range based loops without any specialisations being required?
>
>Because the shared_ptr would need a .begin(), .end() and further
>things required for a loop. And C-style arrays are outdated in

They could easily be implemented implicitly just like here:

char s[] = "hello";
for(auto c: s) cout << c;

But yet again you missed the point.

Bonita Montero

unread,
May 22, 2023, 12:12:56 PM5/22/23
to
Am 22.05.2023 um 18:06 schrieb Mut...@dastardlyhq.com:

> They could easily be implemented implicitly just like here:
>
> char s[] = "hello";
> for(auto c: s) cout << c;
>
> But yet again you missed the point.

No, if the shared_ptr should behave like a container you'd need
an iterator-type with * and ++ and a begin and end-method on the
shared_ptr. I think the C++ designers thought this isn't necessary.

Pavel

unread,
May 22, 2023, 11:22:18 PM5/22/23
to
Well, there are (up to) 2 different Ns. First N is a bound of template
parameter when it is an array with a known bound. Second N is that
number of elements that compiler knows (in the implementation-dependent
way) when array delete expression destroys the objects.

If begin() and end() on shared_ptr were defined, would these lines
remain legal C++ code?

shared_ptr<mystruct[3]> spt1(new mystruct[2]); // (a)


shared_ptr<mystruct[2]> spt2(new mystrucct[3]); // (b)


shared_ptr<mystruct[2]> spt3(getNFromFile()); // (c)

?

If yes, how many elements would range loop iterate thru?

I think maybe if the Standard only allowed shared_ptr specialization
with an array of unknown bound, the behavior of end() would be
technically easier to define (but still difficult to implement as any
implementation-specific feature).

Still, this would take us beyond smart pointer design goal -- which is
in essence to improve on safety of a raw pointer while preserving as
many of the raw pointer capabilities as possible. If we need an array,
we have std::array; if we have a vector, we have std::vector and
std::valarray.

(I personally think it is a shame that we don't have an exact-size
vector (i.e. a vector sized like valarray, with no capacities) but still
it is not a good excuse to abuse poor little smart pointers. For the
exact-size vector, using new[]- allocated memory and compiler trickery
for N could be justified).

-Pavel

Alf P. Steinbach

unread,
May 23, 2023, 1:11:36 AM5/23/23
to
It is.

For example, otherwise my example of how to do this would not work.


> and consider this definition:
>
> shared_ptr<mystruct[3]> sp(new mystruct[2]);
>
> or, even better:
>
> shared_ptr<mystruct[3]> sp(new mystruct[getNOfMyStructs()]);
>
> What can possibly go wrong? (TM)

You shot your leg off.

C++ allows that, in general.

shared_ptr provides support for arrays, including I believe restrictions
on conversions, but not total type safety enforcement.


- Alf

Öö Tiib

unread,
May 23, 2023, 3:14:54 AM5/23/23
to
On Tuesday, 23 May 2023 at 06:22:18 UTC+3, Pavel wrote:
>
> (I personally think it is a shame that we don't have an exact-size
> vector (i.e. a vector sized like valarray, with no capacities) but still
> it is not a good excuse to abuse poor little smart pointers. For the
> exact-size vector, using new[]- allocated memory and compiler trickery
> for N could be justified).
>
IOW it is shame that the implementation-dependent way of figuring
how many destructors to call with delete[] to pointer allocated with
new[] is not exposed to programmers for to write such a class
themselves if the standard library does not bother.

Mut...@dastardlyhq.com

unread,
May 23, 2023, 4:17:25 AM5/23/23
to
Well they thought it necessary to be able to store arrays and index them
inside a shared pointer, so why didn't they complete the job?

Bonita Montero

unread,
May 23, 2023, 4:20:19 AM5/23/23
to
Am 23.05.2023 um 10:17 schrieb Mut...@dastardlyhq.com:

> Well they thought it necessary to be able to store arrays and index
> them inside a shared pointer, so why didn't they complete the job?

No need to worry about that because there is a workaround that has
other benefits as well.

Mut...@dastardlyhq.com

unread,
May 23, 2023, 4:24:52 AM5/23/23
to
Yes I know, but thats not the point. If they going to add features to the
language why don't they do it properly instead of some half assed job?

Bonita Montero

unread,
May 23, 2023, 9:46:11 AM5/23/23
to
Am 23.05.2023 um 10:24 schrieb Mut...@dastardlyhq.com:

> Yes I know, but thats not the point. If they going to add features to the
> language why don't they do it properly instead of some half assed job?

For me the current solution is proper enough.
C-style arrays aren't very common in C++.


james...@alumni.caltech.edu

unread,
May 24, 2023, 12:39:55 AM5/24/23
to
On Thursday, May 18, 2023 at 5:10:57 AM UTC-4, Mut...@dastardlyhq.com wrote:
> Is there a way to get range loops to work with arrays stored in
> shared pointers?
>
> eg:
>
> #include <iostream>
> #include <memory>
>
> using namespace std;
>
> struct mystruct
> {
> mystruct() { cout << "Con " << this << endl; };
> ~mystruct() { cout << "Dest " << this << endl; }
> void func() { cout << "Func " << this << endl; }
> };
>
>
> int main()
> {
> shared_ptr<mystruct[3]> sp(new mystruct[3]);
> sp[0].func();
> sp[1].func();
> sp[2].func();
> for(auto &ms: sp.get()) ms.func(); <--- Doesn't compile
> return 0;
> }
>
> I've tried other combinations too, nothing works.

Would this be an acceptable alternative? It compiles and executes as I expected it to:

#include <iostream>
#include <memory>

using namespace std;

struct mystruct
{
mystruct() { cout << "Con " << this << endl; };
~mystruct() { cout << "Dest " << this << endl; }
void func() { cout << "Func " << this << endl; }
};


int main()
{
shared_ptr<mystruct[1][3]> sp(new mystruct[1][3]);
sp[0][0].func();
sp[0][1].func();
sp[0][2].func();
for(auto &ms: sp.get()[0]) ms.func(); // <--- Doesn't compile
return 0;
}

Mut...@dastardlyhq.com

unread,
May 24, 2023, 4:51:07 AM5/24/23
to
On Tue, 23 May 2023 21:39:46 -0700 (PDT)
"james...@alumni.caltech.edu" <james...@alumni.caltech.edu> wrote:
>On Thursday, May 18, 2023 at 5:10:57=E2=80=AFAM UTC-4, Mut...@dastardlyhq.c=
>om wrote:
>> I've tried other combinations too, nothing works.
>
>Would this be an acceptable alternative? It compiles and executes as I expe=
>cted it to:

Clang doesn't like it I'm afraid:

fenris$ c++ -std=c++17 t.cc
t.cc:16:32: error: no matching constructor for initialization of 'shared_ptr<mys
truct[1][3]>'

Bonita Montero

unread,
May 24, 2023, 9:01:18 AM5/24/23
to
It compiled for me with clang++ 14.

james...@alumni.caltech.edu

unread,
May 24, 2023, 12:48:14 PM5/24/23
to
On my machine, it works:

clang++-14 -std=c++17 shared_pointer.cpp -o shared_pointer

clang++-14 --version
Ubuntu clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Pavel

unread,
May 24, 2023, 9:13:32 PM5/24/23
to
Actually, I meant someone slightly different. The shame is that the
vector class is not factored onto an exact-size array (let's call it
"block") and the rest of vector functionality.

vector has the design flaw that it is too many things: it is the owner
of several contiguous objects in memory but also the growth strategy.

The block is useful independently of vector if:

a) a custom growth strategy is needed; or
b) no growth is needed at all (a very often case in my practice).

For small vectors, replacing them with blocks could provide significant
space savings (not limited by only capacity even when compiler trickery
is not used; e.g. block<size_t> could be specialized so that the
underlying storage layout is implemented like this:

struct { const size_t N; size_t data[]; }; // or like this
struct { const size_t *end; size_t data[]; };

This way, 2 words of memory are saved (capacity and begin pointer) and
one indirection is also saved when one needs to access elements in a
block passed by reference or pointer so this brings both performance and
space savings.

Then, as I said, for the purpose of implementing the block (again, maybe
of only some specializations), using compiler trickery for computing N
*could* be justified. *could* is a keyword here. It *could* also be
useless or even detrimental performance-wise. It is feasible that the

operator new[]

would actually take more memory from the OS for N elements than
(non-array) allocation function

void* operator new(size[, align_val_t]...)

would for the same N elements. In this case, no gain is achieved from
using operator new[] and compiler trickery over using the single-object
form of allocation function "operator new" and system-independent
implementation.

-Pavel


Pavel

unread,
May 24, 2023, 9:16:44 PM5/24/23
to
The support of indexing can be considered to be the support of the
existing functionality of a raw pointer as it also supports indexing,
but not iteration.

-Pavel

Pavel

unread,
May 24, 2023, 9:42:26 PM5/24/23
to
Yes, but notice that for Mutley, it seemed more natural that N was the
the run-time size of the array (somewhere up this thread he used the
argument that the compiler is able to get N to destroy every of N
allocated objects when delete[] is called -- on raw pointer -- that does
not have compile-time N). This tells me that different people would feel
differently about which N is "natural" (compile-time or runtime) so
standardizing this would be counter-intuitive either way.

>
>
>> and consider this definition:
>>
>> shared_ptr<mystruct[3]> sp(new mystruct[2]);
>>
>> or, even better:
>>
>> shared_ptr<mystruct[3]> sp(new mystruct[getNOfMyStructs()]);
>>
>> What can possibly go wrong? (TM)
>
> You shot your leg off.
I certainly did. This is exactly why I do not mind if this particular
way to self-inflict harm on myself is not supported :-). smart pointers
were supposed to be safer than the raw ones, after all, and even raw
pointers do not support iteration.

>
> C++ allows that, in general.
Yes, that was one of the design goals. Blow up your whole leg.. Going on
tangent, I am still mad at them they broke this performance-over-safety
promise when they decided that most-derived-class's virtual function
cannot be called from a constructor or destructor of a base class.
"What's safe enough for Java should be safe enough for C++" says I :-).

>
> shared_ptr provides support for arrays,
I disagree. I think what you mean by "support for array" (indexing?) is
actually the support for the raw pointers to memory allocated by
operator new[]. The argument that we pass to the shared_ptr constructor in

shared_ptr<mystruct[3]> sp(new mystruct[3]);

(and that the shared_ptr likely stores underneath) is such a raw
pointer, not an array.

> including I believe restrictions
> on conversions, but not total type safety enforcement.
>
>
> - Alf
>

-Pavel

Chris M. Thomasson

unread,
May 25, 2023, 12:22:52 AM5/25/23
to
On 5/24/2023 6:40 PM, Pavel wrote:
> Alf P. Steinbach wrote:
>> On 2023-05-21 5:53 AM, Pavel wrote:
>>> Alf P. Steinbach wrote:
>>>> On 2023-05-20 5:19 AM, Pavel wrote:
>>>>> Mut...@dastardlyhq.com wrote:
>>>>>> Is there a way to get range loops to work with arrays stored in
>>>>>> shared pointers?
>>>>> These shared pointers do not store arrays. They store pointers to
>>>>> memory object allocated with operator new[].
[...]
>> shared_ptr provides support for arrays,
> I disagree. I think what you mean by "support for array" (indexing?) is
> actually the support for the raw pointers to memory allocated by
> operator new[]. The argument that we pass to the shared_ptr constructor in
>
> shared_ptr<mystruct[3]> sp(new mystruct[3]);
>
> (and that the shared_ptr likely stores underneath) is such a raw
> pointer, not an array.
[...]

Almost has to be.


Mut...@dastardlyhq.com

unread,
May 25, 2023, 4:51:30 AM5/25/23
to
On Wed, 24 May 2023 09:48:05 -0700 (PDT)
"james...@alumni.caltech.edu" <james...@alumni.caltech.edu> wrote:
>On Wednesday, May 24, 2023 at 4:51:07=E2=80=AFAM UTC-4, Mut...@dastardlyhq.=
>com wrote:
>> On Tue, 23 May 2023 21:39:46 -0700 (PDT)=20
>> "james...@alumni.caltech.edu" <james...@alumni.caltech.edu> wrote:=20
>> >On Thursday, May 18, 2023 at 5:10:57=3DE2=3D80=3DAFAM UTC-4, Mut...@dast=
>ardlyhq.c=3D
>> >om wrote:=20
>> >> I've tried other combinations too, nothing works.=20
>> >
>> >Would this be an acceptable alternative? It compiles and executes as I e=
>xpe=3D=20
>> >cted it to:=20
>>=20
>> Clang doesn't like it I'm afraid:=20
>>=20
>> fenris$ c++ -std=3Dc++17 t.cc=20
>> t.cc:16:32: error: no matching constructor for initialization of 'shared_=
>ptr<mys=20
>> truct[1][3]>'
>> shared_ptr<mystruct[1][3]> sp(new mystruct[1][3]);
>
>On my machine, it works:
>
>clang++-14 -std=3Dc++17 shared_pointer.cpp -o shared_pointer
>
>clang++-14 --version
>Ubuntu clang version 14.0.6
>Target: x86_64-pc-linux-gnu
>Thread model: posix
>InstalledDir: /usr/bin

Beats me. I'm using clang on a Mac and I tried it again in case I'd not
cut and pasted properly but it still failed.

However this wouldn't be the first time the Apple version of Clang differs
from versions on other platforms.

james...@alumni.caltech.edu

unread,
May 26, 2023, 3:49:43 AM5/26/23
to
On Thursday, May 25, 2023 at 4:51:30 AM UTC-4, Mut...@dastardlyhq.com wrote:
> On Wed, 24 May 2023 09:48:05 -0700 (PDT)
> "james...@alumni.caltech.edu" <james...@alumni.caltech.edu> wrote:
> >On Wednesday, May 24, 2023 at 4:51:07=E2=80=AFAM UTC-4, Mut...@dastardlyhq.=
> >com wrote:
...
> >> Clang doesn't like it I'm afraid:=20
> >>=20
> >> fenris$ c++ -std=3Dc++17 t.cc=20
> >> t.cc:16:32: error: no matching constructor for initialization of 'shared_=
> >ptr<mys=20
> >> truct[1][3]>'
> >> shared_ptr<mystruct[1][3]> sp(new mystruct[1][3]);
> >
> >On my machine, it works:
> >
> >clang++-14 -std=3Dc++17 shared_pointer.cpp -o shared_pointer
> >
> >clang++-14 --version
> >Ubuntu clang version 14.0.6
> >Target: x86_64-pc-linux-gnu
> >Thread model: posix
> >InstalledDir: /usr/bin
> Beats me. I'm using clang on a Mac and I tried it again in case I'd not
> cut and pasted properly but it still failed.
>
> However this wouldn't be the first time the Apple version of Clang differs
> from versions on other platforms.

Something about that error message makes me suspicious that the
problem may be more fundamental. Does it still complain if you change it
to use a raw pointer, rather than a shared_pointer?:

mystruct(*sp)[3](new mystruct[1][3]);
...
for(auto &ms: sp[0]) ms.func();
...
delete[] sp;

Mut...@dastardlyhq.com

unread,
May 26, 2023, 4:44:25 AM5/26/23
to
On Fri, 26 May 2023 00:49:32 -0700 (PDT)
"james...@alumni.caltech.edu" <james...@alumni.caltech.edu> wrote:
>On Thursday, May 25, 2023 at 4:51:30=E2=80=AFAM UTC-4, Mut...@dastardlyhq.c=
>om wrote:
>> Beats me. I'm using clang on a Mac and I tried it again in case I'd not=
>=20
>> cut and pasted properly but it still failed.=20
>>=20
>> However this wouldn't be the first time the Apple version of Clang differ=
>s=20
>> from versions on other platforms.
>
>Something about that error message makes me suspicious that the
>problem may be more fundamental. Does it still complain if you change it
>to use a raw pointer, rather than a shared_pointer?:
>
>mystruct(*sp)[3](new mystruct[1][3]);=20
>....
>for(auto &ms: sp[0]) ms.func();
>....
>delete[] sp;

No, that compiles fine. Looks like the current Mac version of Clang does
have a bug but given how infrequently Apple updates their compiler I won't
hold my breath on it being fixed anytime soon.

Bonita Montero

unread,
May 26, 2023, 7:16:10 AM5/26/23
to
Am 26.05.2023 um 10:44 schrieb Mut...@dastardlyhq.com:

> No, that compiles fine. Looks like the current Mac version of Clang does
> have a bug but given how infrequently Apple updates their compiler I won't
> hold my breath on it being fixed anytime soon.

AFAIK you can replace Apple's clang with LLVM clang somhehow.


Öö Tiib

unread,
May 26, 2023, 8:59:11 AM5/26/23
to
Yes, <https://releases.llvm.org/> can download distributions for Apple too.

Mut...@dastardlyhq.com

unread,
May 26, 2023, 11:02:04 AM5/26/23
to
Every new release of MacOS locks things down more and more. I'm a bit
paranoid about updating something as fundamental as the compiler and all
the libraries as I have a nasty feeling things might die halfway through with
some system integrity or unsigned code error or similar.

Bonita Montero

unread,
May 26, 2023, 1:20:14 PM5/26/23
to
I think a compiler is much more fundamental for Linux than for macOS.


Mut...@dastardlyhq.com

unread,
May 27, 2023, 5:30:17 AM5/27/23
to
MacOS internals are somewhat opaque. I'd rather not take the risk as I use my
Mac for far more than just writing C++ and if it died I'd be screwed even
with data backups.

0 new messages