Two nested classes are tied together.

N

Nephi Immortal

I create one main class. I use three data members to do addition
between left value and right value through reference. It is the
standard C++ code as common practice.
Look at the code below and see my comments.

class Data
{
public:
Data() : x( 0 ), y( 0 ), z( 0 )
{
}

Data( int _x, int _y, int _z ) : x( _x ), y( _y ), z( _z )
{
}

~Data()
{
}

Data( const Data &rData ) : x( rData.x ), y( rData.y ), z( rData.z )
{
}

Data &operator=( const Data &rData )
{
if( this == &rData )
return *this;

x = rData.x;
y = rData.y;
z = rData.z;

return *this;
}

Data &operator+=( const Data &rData )
{
x += rData.x;
y += rData.y;
z += rData.z;

return *this;
}

Data operator+( const Data &rData )
{
Data temp( *this );
return ( temp += rData );
}


private:
int x;
int y;
int z;
};

int main()
{
Data d1( 1, 2, 3 ), d2( 4, 5, 6 ), d3( 7, 8, 9 );

d1 = d2 + d3;

return 0;
}


My code looks fine. I decide to design nested classes inside main
class. They are inner classes and are hidden from the client. The
client uses Proxy() function to access nested class’ functions.
I create two helper classes. Both of them are tied or related
together. It is necessary because I put reference on data member:
rData. The Data class remains unmodified through Proxy class’
reference unless you never place any Object class’ data members inside
Proxy class or they will be modified.
I choose reference instead of copy of value because if I add more
data members in Data class, constructor function will copy all data
members every time it is called and destroyed. It would be overhead
on CPU.
I traced my code through debugger and tested all data members being
pushed into and popped out of stack in the correct order. Everything
is working properly.
How can you assure that my code is NOT undefined behavior?


class Object
{
private:
class _Proxy;
class Data
{
public:
Data() : x( 0 ), y( 0 ), z( 0 )
{
}

Data( int _x, int _y, int _z ) : x( _x ), y( _y ), z( _z )
{
}

~Data()
{
}

Data( const Data &_rData ) : x( _rData.x ), y( _rData.y ),
z( _rData.z )
{
}

Data &operator=( const Data &_rData )
{
if( this == &_rData )
return *this;

x = _rData.x;
y = _rData.y;
z = _rData.z;

return *this;
}

Data &operator+=( const Data &_rData )
{
x += _rData.x;
y += _rData.y;
z += _rData.z;

return *this;
}

Data operator+( const _Proxy &_rProxy )
{
Data temp( *this );
return ( temp += _rProxy.rData );
}

//private: /* Put Data class inside outer class. */
int x;
int y;
int z;
};

Data _data;

class _Proxy
{
public:
_Proxy( Data &_data ) : rData( _data )
{
}

~_Proxy()
{
}

_Proxy &operator=( const _Proxy &_rProxy )
{
if( this == &_rProxy )
return *this;

rData = _rProxy.rData;
return *this;
}

_Proxy &operator=( const Data &_rData )
{
rData = _rData;
return *this;
}

_Proxy &operator+=( const _Proxy &_rProxy )
{
rData += _rProxy.rData;
return *this;
}

Data operator+( const _Proxy &_rProxy )
{
Data temp( rData );
temp += _rProxy.rData;
return temp;
}

//private: /* Put _Proxy class inside outer class. */
Data &rData; // Reference
};

public:
Object() : _data( 0, 0, 0 )
{
}

Object( int _x, int _y, int _z ) : _data( _x, _y, _z )
{
}

~Object()
{
}

Object( const Object &rObject ) : _data( rObject._data )
{
}

Object &operator=( const Object &rObject )
{
if( this == &rObject )
return *this;

_data = rObject._data;

return *this;
}

_Proxy Proxy() // _Proxy is copy of value
{
return _Proxy( _data ); // _data is reference
}

};




int main()
{
Object object1, object2( 1, 2, 3 ), object3( 4, 5, 6 ), object4( 7,
8, 9 ), object5( 10, 11, 12 );

object1.Proxy() = object2.Proxy() + object3.Proxy() + object4.Proxy()
+ object5.Proxy();

object2.Proxy() = object3.Proxy();
object2.Proxy() += object4.Proxy();

object4 = object1;

return 0;
}
 
N

Nephi Immortal

This should be 'const' or a free function.












Using such a name is UB, so definitely your code has undefined behavior
;-)

If you rename this class, your code seems to OK at the first glance. It
is a bit fragile as one must take care that an Object is not destroyed
before a corresponding Proxy. I would add some safeguards for such a
design, at least in Debug builds, e.g. each Proxy would increase a
counter in the Object while it's alive, and the Object's destructor
asserts that the counter has reached zero again.

“If you rename this class”

I truly do not understand your point. What are you trying to clarify
that you rename a class name? Please clarify. I don’t see any
undefined behavior.

You said Object *possibly* calls destructor function before Data and
Proxy call destructor function. It does not make any sense. If you
look at the stack, you will see that Data and Proxy call destructor
function and are popped out of stack before Object calls destructor
function.

Try to test your code. Move Data class and Proxy class outside Object
class. Define Data variable and Proxy variable in main function. You
will see nothing is wrong. They are working properly as long as
undefined behavior never occurs.

I do not want the client to access Data class and Proxy class
directly. They are placed inside Object class in private. The
safeguard is sufficient maximum.

You do not need to use counter in destructor class unless you want to
use dynamic array.

Please answer my question. Notice two functions in Proxy class below.

Data operator+( const _Proxy &_rProxy )
Proxy &operator=( const Data &_rData )

Both Data class and Proxy class are *tied* together.

If you design single class, the return type and function parameter
type must be identical.
 
R

red floyd

“If you rename this class”

I truly do not understand your point. What are you trying to clarify
that you rename a class name? Please clarify. I don’t see any
undefined behavior.

Any identifier with a leading underscore followed by an upper-case
letter is reserved to the implementation in ANY scope. This means
that you may not use such identifiers (like _Proxy) for your own
purposes.

What Paavo was saying is that outside of this issue, your code
looks OK.
 
N

Nephi Immortal

Any identifier with a leading underscore followed by an upper-case
letter is reserved to the implementation in ANY scope.  This means
that you may not use such identifiers (like _Proxy) for your own
purposes.

What Paavo was saying is that outside of this issue, your code
looks OK.- Hide quoted text -

OK. Paavo was saying is that my code is OK. What is he referring
“OK”? I guess to be the fact as poor design. If you answer yes,
please clarify why you think that the design is poor? Tell me more
reasons. Perhaps, you express your opinion.

I assume. You perhaps say do not use reference on all data members
and always declare value type or pointer. Explain the reason. Maybe,
reference is not the option because it leads to undefined behavior.
 
N

Nephi Immortal

Any identifier with a leading underscore followed by an upper-case
letter is reserved to the implementation in ANY scope.  This means
that you may not use such identifiers (like _Proxy) for your own
purposes.

You refer underscore with name is implementation. I think you refer
an example -- _Vector_const_iterator and _Vector_iterator. The client
can’t use either _Vector_const_iterator or _Vector_iterator. He needs
to use vector instead because vector is inherited from
_Vector_const_iterator and _Vector_iterator.

I think it is ok to use these name like _Data and _Proxy because they
are inaccessible to the client when they are protected in this parent
class.
 
I

Ian Collins

You refer underscore with name is implementation. I think you refer
an example -- _Vector_const_iterator and _Vector_iterator. The client
can’t use either _Vector_const_iterator or _Vector_iterator. He needs
to use vector instead because vector is inherited from
_Vector_const_iterator and _Vector_iterator.

I think it is ok to use these name like _Data and _Proxy because they
are inaccessible to the client when they are protected in this parent
class.

What parts of "reserved to the implementation" and "you may not use"
weren't clear?
 
R

red floyd

Is it UB, or is the code simply ill-formed?

From [lib.reserved.names]:

"The C + + Standard Library reserves the following kinds of names:
[...]
— Global names
[...]
If the program declares or defines a name in a context where it is
reserved, other than as explicitly allowed by this clause, the behavior
is undefined."

Thanks, Paavo, I didn't have my copy of the Standard available at the
time, and I couldn't remember what it said. I just wasn't sure which
"error" condition it was considered -- UB or ill-formed.

Much obliged.
 
T

TJorgenson

I think it is ok to use these name like _Data and _Proxy because they
are inaccessible to the client when they are protected in this parent
class.- Hide quoted text -

The compiler is allow to create a macro with these names as well.
Macros can't be scoped.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top