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

Re: faster than c

110 views
Skip to first unread message
Message has been deleted

Ian Collins

unread,
Apr 19, 2015, 12:52:42 AM4/19/15
to
Stefan Ram wrote:
> Newsgroups: comp.lang.c,comp.lang.c++
>
> Ian Collins <ian-...@hotmail.com> writes:
>> Again, this would be problematic in C++, unless the object is const. So
>> one could have:
>> const int* y = std::begin({ 1, 2, 3 });
>
> What is this? { 1, 2, 3 } seems to be used to initialize a
> temporary object whose lifetimes ends at the semicolon, so
> the pointer y then would be dangling?

It's an initialiser list. To quote cplusplus.com:

"initializer_list objects are automatically constructed as if an array
of elements of type T was allocated, with each of the elements in the
list being copy-initialized to its corresponding element in the array,
using any necessary non-narrowing implicit conversions."

So while the object is a temporary, the data it references is not. Note
that the return type of std::begin() is a const T* (constexpr in C++14).

--
Ian Collins

Paavo Helde

unread,
Apr 19, 2015, 10:27:32 AM4/19/15
to
Ian Collins <ian-...@hotmail.com> wrote in
news:cpgqkd...@mid.individual.net:

> Stefan Ram wrote:
>> Newsgroups: comp.lang.c,comp.lang.c++
>>
>> Ian Collins <ian-...@hotmail.com> writes:
>>> Again, this would be problematic in C++, unless the object is const.
>>> So one could have:
>>> const int* y = std::begin({ 1, 2, 3 });
>>
>> What is this? { 1, 2, 3 } seems to be used to initialize a
>> temporary object whose lifetimes ends at the semicolon, so
>> the pointer y then would be dangling?
>
> It's an initialiser list. To quote cplusplus.com:
>
> "initializer_list objects are automatically constructed as if an array
> of elements of type T was allocated, with each of the elements in the
> list being copy-initialized to its corresponding element in the array,
> using any necessary non-narrowing implicit conversions."
>
> So while the object is a temporary, the data it references is not.

There is no data object the y pointer could point to. 1 is a rvalue whose
address cannot be taken, and any other objects constructed from it and
initialized to 1 are not guaranteed to be alive.

Quoting from cppreference.com: "The underlying array is a temporary
array, in which each element is copy-initialized (except that narrowing
conversions are invalid) from the corresponding element of the original
initializer list. The lifetime of the underlying array is the same as any
other temporary object [...]"

So, as the array is temporary, a pointer to its element can and will
become dangling as far as I can see.

Cheers
Paavo



Ian Collins

unread,
Apr 20, 2015, 3:53:07 AM4/20/15
to
I thought the clarification (making the return value a constexpr) takes
care of that. Certainly the generated code I've checked for a couple of
compilers shows the values being accessed from static data. For example
gcc -O3 -std=c++11 (or -O3 -std=c++14) compiles


int c();

int f()
{
const int* y = std::begin({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

return y[c()];
}

as

_Z1fv:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _Z1cv
movl ._0(,%eax,4), %eax
leave
ret

where ._0 is
._0:
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.long 7
.long 8
.long 9
.long 10

and

int f()
{
const int* y = std::begin({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

return y[4];
}

as

_Z1fv:
movl $5, %eax
ret

:)

--
Ian Collins
Message has been deleted

Ian Collins

unread,
Apr 21, 2015, 12:36:17 AM4/21/15
to
Stefan Ram wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>> Paavo Helde wrote:
>>>>> Ian Collins <ian-...@hotmail.com> writes:
>>>>>> const int* y = std::begin({ 1, 2, 3 });
>>> So, as the array is temporary, a pointer to its element can and will
>>> become dangling as far as I can see.
>> I thought the clarification (making the return value a constexpr) takes
>
> »constexpr« did not occur so far. A const& can extend the
> lifetime of a temporary, but it must be bound to it directly,
> not via a pointer.
>
> »::std::begin« does not accept an initialization list, only
> an array reference, so a temporary array will be created and
> the begin pointer of that array will be computed. The result
> is a pointer to the begin of that array. Then, that array will
> be destroyed. It is as if

18.9.3 Initializer list range access

template<class E> const E* begin(initializer_list<E> il) noexcept;

1 Returns: il.begin().

> #include <initializer_list>
> #include <iostream>
> #include <ostream>
>
> struct array
> { array( ::std::initializer_list< int >const ){};
> ~array(){ ::std::cout << "I, temporary array, destroyed\n"; } };
>
> int * begin( array ){ return nullptr; }

So this always returns nullptr.

> int main()
> { ::std::cout << "before\n";
> const int * y = begin( { 1, 2, 3 }); /* this is like your code */

So this is equivalent to y = nullptr;

> ::std::cout << "after\n";
> ::std::cout << "y = " << y << '\n'; }
>
> before
> I, temporary array, destroyed
> after
> y = 0

int main()
{
std::cout << "before\n";
const int * y = std::begin( { 1, 2, 3 }); /* this is like your code */
std::cout << "after\n";
std::cout << "y = " << y << '\n';
}

before
after
y = 0x8051294

--
Ian Collins
Message has been deleted
Message has been deleted
0 new messages