From: Cary on
On 8月3日, 上午6時01分, PGK <graham.k...(a)gmail.com> wrote:
> Hi all,
>
> Why is it that an object can be initialised by itself without error?
> What is the purpose of such leniency? For example:
>
> Foo a(a); // No compile error
>
> Cheers,
>
> The output of the subsequent code is:
>
> Out 1: 7
> In 1 : -1149044056
> In 2 : -1149044056
> Out 2: 7
>
> --------------------------------------
>
> #include <iostream>
>
> struct Foo {
> Foo(int x) { m_x = x; }
> Foo(Foo &f) { m_x = f.m_x; }
> int m_x;
>
> };
>
> int main(int argc, char *argv[])
> {
> Foo a(7);
> std::cout << "Out 1: " << a.m_x << std::endl;
> {
> Foo a(a);
> std::cout << "In 1 : " << a.m_x << std::endl;
> Foo b(b);
> std::cout << "In 2 : " << a.m_x << std::endl;
> }
> std::cout << "Out 2: " << a.m_x << std::endl;
>
> return 0;
>
> }
>

In my opinion, this is a well-formed but undefined behavior.
you say "Foo a(a);" you declare the "a" previously, so you can pass it
to self initialize.
but when calling its copy constructor, you use its own indeterminate
value to initialize itself...
mostly if there is a memory management in Foo class, you will got a
seg fault.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Lailoken on
On Aug 2, 3:01 pm, PGK <graham.k...(a)gmail.com> wrote:
> Hi all,
>
> Why is it that an object can be initialised by itself without error?
> What is the purpose of such leniency? For example:
>
> Foo a(a); // No compile error

Because it happens in two distinct parts. Firstly the memory for the
object gets allocated (and the vtbl gets set up), and thus 'a' is
allocated but uninitialized.

Then the object (which still does not have any constructors called) is
passed to its own constructor.

For one thing it may or may not be useful when doing certain types of
object pooling, although I cannot think of a good use at the moment.
(And object pooling is best done by creating class local new and
delete operators)

But it all seems pretty legal to me at first glance.
Hope this helps.

> Cheers,
>
> The output of the subsequent code is:
>
> Out 1: 7
> In 1 : -1149044056
> In 2 : -1149044056
> Out 2: 7
>
> --------------------------------------
>
> #include <iostream>
>
> struct Foo {
> Foo(int x) { m_x = x; }
> Foo(Foo &f) { m_x = f.m_x; }
> int m_x;
>
> };
>
> int main(int argc, char *argv[])
> {
> Foo a(7);
> std::cout << "Out 1: " << a.m_x << std::endl;
> {
> Foo a(a);

This 'a' is initialized with itself, not by the one above. Thus the
constructor basically does nothing.

> std::cout << "In 1 : " << a.m_x << std::endl;
> Foo b(b);
> std::cout << "In 2 : " << a.m_x << std::endl;
> }
> std::cout << "Out 2: " << a.m_x << std::endl;
> return 0;
> }



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: PGK on
> Interestingly and confusingly enough, [3.3.1] also gives examples
> which seem contradictory at first:
>
> const int i = 2;
> { int i[i]; } // declares a local of two integers
>
> const int x = 12;
> { enum { x = x }; } // x is initialized with 12

Yes, the first one seems very like my own example, but
the "outer" i is used instead. I also find it odd that
the block construct will allow usage up until a new declaration:

Foo a(7);
{
std::cout << a.m_x << std::endl; // The outer a
Foo a(8);
std::cout << a.m_x << std::endl; // The inner a
}

produces:

7
8


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Francis Glassborow on
PGK wrote:
>> Interestingly and confusingly enough, [3.3.1] also gives examples
>> which seem contradictory at first:
>>
>> const int i = 2;
>> { int i[i]; } // declares a local of two integers
>>
>> const int x = 12;
>> { enum { x = x }; } // x is initialized with 12
>
> Yes, the first one seems very like my own example, but
> the "outer" i is used instead. I also find it odd that
> the block construct will allow usage up until a new declaration:

Well that is a basic principle for C++ (that comes from C) names only
enter scope when they are declared and code is interpreted simply on
what has been seen so far.

There is an exception to this and that is where you define a function in
a class definition. The definition is always treated s if it was after
the completion of the class definition.

Now back to your question. I raised this issue in the mid 90s and
proposed that the such declarations be ill-formed. Unfortunately there
was already some rather bizarre code that made constructive use of the
facility (for user defined types). No I do not fully understand how they
were using it because it includes hi-jacking the copy ctor but it was
nonetheless in existence and therefore WG21 voted down my proposal
(rightly IMO) but good tools such as PCLINT++ will raise a warning.

What concerns me more than a little is the examples quoted from 3.3.1 as
I think that just adds confusion without any gain. I would hope that
good tools raise warnings for both those as they really are terrible code.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]