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

checking initialization of a _var to a sequence

4 views
Skip to first unread message

Jason Etheridge

unread,
Aug 14, 2002, 2:12:48 AM8/14/02
to Dirk Thomalla
Dirk Thomalla wrote:
> how should be tested if a _var to a sequence is already initialized?
> I cannot find a member function of a _var to a sequence returning this
> information.

This appears to be correct (not something I've ever tried, strangely enough!).

> myseq_var sv; // not initialized => unusable
> bool var_is_initialized = false; // just a flag
> void f() {
> if (!var_is_initialized) {
> // done only once, initialize _var
> sv = new myseq;
> var_is_initialized = true;
> }
> else {
> // use sv
> sv->...
> }
> }

Would work, of course, but isn't too elegant!

> myseq_var sv; // not initialized => unusable
> void f() {
> // is this allowed with uninitialized _var?
> myseq *psv = sv._retn();
> if (psv == NULL) {
> // done only once, initialize _var
> psv = new myseq;
> }
> if (psv == NULL) {
> // (re-)asign ownership
> sv = psv;
> // use sv
> sc->...
> }
> }

Well, it would have to be:

myseq_var sv; // not initialized => unusable
...
myseq *psv = sv._retn();
if (psv == 0) {
// Create a new sequence, stick it in the _var
sv = new myseq;
} else {
// Reclaim ownership
sv = psv;
}

Still pretty rough!

> So, is there a better way for checking the
> initialization state of the _var?
> Or is the answer:
> don't use a _var to a sequence in such a silly way ...

That's probably the best answer... I'd suspect a more appropriate design could
avoid this usage, depending on exactly what you are trying to do.

--
Jason Etheridge mailto:ja...@etheridge.org

Stelios Sfakianakis

unread,
Aug 14, 2002, 4:02:27 AM8/14/02
to
Dirk Thomalla wrote:
> Hi,
>
> how should be tested if a _var to a sequence is already initialized?
> I cannot find a member function of a _var to a sequence returning this
> information.
> [...]
> So, is there a better way for checking the
> initialization state of the _var?
> Or is the answer:
> don't use a _var to a sequence in such a silly way ...
>

Why don't you do just this:

if (sv) {
// initialized
}
else {
// uninitialized
}

or

if (sv == 0) {
// uninitialized
}
else {
// initialized
}

There *should* be an automatic conversion from the _var type to the
pointer held inside the var so this works.

Alternatively you could get the pointer through the operator-> like this:
if (sv.operator ->()) { /* initialized */ }

HTH
Stelios

--
Thus spake the master programmer:
``After three days without programming, life becomes meaningless.''
--- The Tao of Programming

Stelios Sfakianakis

unread,
Aug 14, 2002, 5:34:54 AM8/14/02
to
Dirk Thomalla wrote:

> Stelios Sfakianakis <ss...@ics.forth.gr> wrote:
>
>
>>Why don't you do just this:
>>
>>if (sv) {
>> // initialized
>>}
>
>
> This doesn't work using omniORB, gcc returns:
> "`class FOO::TestSeq_var' used where a `bool' was expected"

>
>
>>or
>>
>>if (sv == 0) {
>> // uninitialized
>>}
>
>
> This doesn't work either, gcc returns:
> "no match for `FOO::TestSeq_var & == int'"
>

Yes you are right (and the compiler also!) but only in the case where
you have fixed-size types.
See below.


>
>>There *should* be an automatic conversion from the _var type to the
>>pointer held inside the var so this works.
>
>

> Sure? From "Advanced CORBA Programming with C++":
>
> class T_Var {
> public:
> T_var();
> T_var(T *);
> T_var(const T_var &);
> ~T_var();
>
> T_var() operator=(T *);
> T_var() operator=(const T_var &);
> T * operator->();
> const T * operator->() const;
>
> operator T &();
> operator const T &() const;
>
> TE & operator[](CORBA::ULong);
> const TE & operator[](CORBA::ULong) const;
>
> const T & in() const;
> T & inout();
> T * & out();
> T * _retn();
> };
>
> So operator->() and _retn() are the only member functions which allow
> access to T*.

Yes but from the same source (paragraph 6.19.4) we learn that "_var
classes for variable-length types have an extra conversion operator"
which is `operator T * &()'.

It just happened to test the code I supplied with a sequence with
variable length elements!

Cheers
Stelios

>
>
>>Alternatively you could get the pointer through the operator-> like this:
>>if (sv.operator ->()) { /* initialized */ }
>
>

> This works. Seems to be the best solution so far.
>
>
>>HTH
>
>
> Yes, thanks.

Stelios Sfakianakis

unread,
Aug 14, 2002, 7:24:40 AM8/14/02
to
Dirk Thomalla wrote:
> Stelios Sfakianakis <ss...@ics.forth.gr> wrote:
>
>
>>>So operator->() and _retn() are the only member functions which allow
>>>access to T*.
>>
>>Yes but from the same source (paragraph 6.19.4) we learn that "_var
>>classes for variable-length types have an extra conversion operator"
>>which is `operator T * &()'.
>
>
> Right, I've missed that one.
> But "operator T * &()" is a reference to a pointer, not the pointer
> itself.
>

Yes, it's a reference to the internal pointer, but this does not affect
us as long as you don't write something like "if (sv = 0) { }" :-)

>
>>It just happened to test the code I supplied with a sequence with
>>variable length elements!
>
>

> I'm actually using an unbound sequence.
> /***/
> typedef sequence<string> MySeq;
> /***/
>
> The generated class from 'omniidl -bcxx -Wba' is:
>
> /***/
> class MySeq_var {
> public:
> typedef MySeq T;
> typedef MySeq_var T_var;
> inline MySeq_var() : _pd_seq(0) {}
> inline MySeq_var(T* s) : _pd_seq(s) {}
> inline MySeq_var(const T_var& s) {
> if( s._pd_seq ) _pd_seq = new T(*s._pd_seq);
> else _pd_seq = 0;
> }
> inline ~MySeq_var() { if( _pd_seq ) delete _pd_seq; }
> inline T_var& operator = (T* s) {
> if( _pd_seq ) delete _pd_seq;
> _pd_seq = s;
> return *this;
> }
> inline T_var& operator = (const T_var& s) {
> if( s._pd_seq ) {
> if( !_pd_seq ) _pd_seq = new T;
> *_pd_seq = *s._pd_seq;
> } else if( _pd_seq ) {
> delete _pd_seq;
> _pd_seq = 0;
> }
> return *this;
> }
> inline _CORBA_String_element operator [] (_CORBA_ULong s) {
> return (*_pd_seq)[s];
> }
> inline T* operator -> () { return _pd_seq; }
> #if defined(__GNUG__) && __GNUG__ == 2 && __GNUC_MINOR__ == 7
> inline operator T& () const { return *_pd_seq; }
> #else
> inline operator const T& () const { return *_pd_seq; }
> inline operator T& () { return *_pd_seq; }
> #endif
> inline const T& in() const { return *_pd_seq; }
> inline T& inout() { return *_pd_seq; }
> inline T*& out() {
> if( _pd_seq ) { delete _pd_seq; _pd_seq = 0; }
> return _pd_seq;
> }
> inline T* _retn() { T* tmp = _pd_seq; _pd_seq = 0; return tmp; }
>
> friend class MySeq_out;
> private:
> T* _pd_seq;
> };
> /***/
>
> So, no operator T * &() in there. A bug in omniidl?
>

I would say so. The TAO generated stub for the same type is:

// *************************************************************
// class test::MySeq_var
// *************************************************************

class MySeq_var
{
public:
MySeq_var (void);
MySeq_var (MySeq *);
MySeq_var (const MySeq_var &);
~MySeq_var (void);

MySeq_var &operator= (MySeq *);
MySeq_var &operator= (const MySeq_var &);
MySeq *operator-> (void);
const MySeq *operator-> (void) const;

operator const MySeq &() const;
operator MySeq &();
operator MySeq &() const;
operator MySeq *&(); // variable-size base types only

TAO_SeqElem_String_Manager operator[] (CORBA::ULong index);

// in, inout, out, _retn
const MySeq &in (void) const;
MySeq &inout (void);
MySeq *&out (void);
MySeq *_retn (void);
MySeq *ptr (void) const;

private:
MySeq *ptr_;
};

As you can see there is the operator MySeq *&() defined with a comment
also that this operator was generated because it is a variable-size type.

In any case it seems that the trick with the operator-> is a more
general solution so you 'd better use that.

Regards
Stelios

Michi Henning

unread,
Aug 15, 2002, 7:48:42 AM8/15/02
to
"Dirk Thomalla" <di...@srx6.de> wrote in message
news:2j8iluc4dkc68lusf...@4ax.com...

> Hi,
>
> how should be tested if a _var to a sequence is already initialized?
> I cannot find a member function of a _var to a sequence returning this
> information.


Hmmm... Why do you need to do that? I'm asking because
I've never had the need to do this in my code up to now.
If you insist, you can use

if (sv.operator->())
// sv is initialized...

but it's not all that pretty.

There is no default conversion to bool or anything like that.

Cheers,

Michi.

--
Michi Henning Ph: +61 4 1118-2700
Triodia Technologies http://www.triodia.com/staff/michi


Gary Duzan

unread,
Aug 16, 2002, 4:56:26 PM8/16/02
to
In article <3D5A3DF8...@ics.forth.gr>,
Stelios Sfakianakis <ss...@ics.forth.gr> wrote:
=>Dirk Thomalla wrote:
=>> Stelios Sfakianakis <ss...@ics.forth.gr> wrote:
=>>
=>> So, no operator T * &() in there. A bug in omniidl?
=>>
=>
=>I would say so.

I would say not.

=> The TAO generated stub for the same type is:
=>
=> // *************************************************************
=> // class test::MySeq_var
=> // *************************************************************
=>
=> class MySeq_var
=> {
=> public:
=> // [ ... ]
=> operator const MySeq &() const;
=> operator MySeq &();
=> operator MySeq &() const;
=> operator MySeq *&(); // variable-size base types only
=> // [ ... ]
=> };
=>
=>As you can see there is the operator MySeq *&() defined with a comment
=>also that this operator was generated because it is a variable-size type.

The only problem with that reasoning is that neither H&V nor
TAO is the spec. The C++ Language Mapping gives the general form
of T_var types for structured types T in section 1.9.1, and the
specific form for sequence types in section 1.13.4, neither of
which makes any mention of an "operator T * &()". H&V and TAO are
providing ORB-specific extensions.

=>In any case it seems that the trick with the operator-> is a more
=>general solution so you 'd better use that.

That's a much better idea. However, it is still not guaranteed
to work since, "Compliant applications may not attempt to convert
a T_var created with the default constructor into a T* nor use its
overloaded operator-> without first assigning to it a valid T* or
another valid T_var." [section 1.9.1] Practically speaking, I
imagine it will work in most implementations. YMMV.

Gary Duzan
BBN Technologies
A Verizon Company


Michi Henning

unread,
Aug 16, 2002, 5:40:27 PM8/16/02
to
"Gary Duzan" <ga...@duzan.org> wrote in message news:3d5d66fa$1...@nopics.sjc...

> In article <3D5A3DF8...@ics.forth.gr>,
> Stelios Sfakianakis <ss...@ics.forth.gr> wrote:
> =>Dirk Thomalla wrote:
> => class MySeq_var
> => {
> => public:
> => // [ ... ]
> => operator const MySeq &() const;
> => operator MySeq &();
> => operator MySeq &() const;
> => operator MySeq *&(); // variable-size base types only
> => // [ ... ]
> => };
> =>
> =>As you can see there is the operator MySeq *&() defined with a comment
> =>also that this operator was generated because it is a variable-size type.
>
> The only problem with that reasoning is that neither H&V nor
> TAO is the spec. The C++ Language Mapping gives the general form
> of T_var types for structured types T in section 1.9.1, and the
> specific form for sequence types in section 1.13.4, neither of
> which makes any mention of an "operator T * &()". H&V and TAO are
> providing ORB-specific extensions.

No, that's not correct. It is true that operator T * &() is not shown
explicitly in section 1.9.1 of the C++ mapping. However, the mapping
does show the following at the end of the T_var class:

// other conversion operators to support
// parameter passing

The test then goes on to say the following:

In addition to the member functions described above, the T_var types must
support
conversion functions that allow them to fully support the parameter passing
modes
shown in “Basic Argument and Result Passing” on page 1-105. The form of
these
conversion functions is not specified so as to allow different
implementations, but the
conversions must be automatic (i.e., they must require no explicit
application code to
invoke them).

For sequences, inout parameters are passed as T * & (according to
Table 1-3). For it to be possible for a T_var to be transparently
passed as a T * &, the T_var must have a conversion that allows
the compiler to match arguments. So, while not explicitly shown,
the operator T * &() is implied by the text. (Strictly speaking,
that particular operator need not be present, provided that there
is some sequence of conversions that would allow a T_var to
be passed where a T * &() is expected; but, off-hand, I can't
think of any.)

> =>In any case it seems that the trick with the operator-> is a more
> =>general solution so you 'd better use that.
>
> That's a much better idea. However, it is still not guaranteed
> to work since, "Compliant applications may not attempt to convert
> a T_var created with the default constructor into a T* nor use its
> overloaded operator-> without first assigning to it a valid T* or
> another valid T_var." [section 1.9.1] Practically speaking, I
> imagine it will work in most implementations. YMMV.

What the mapping really meant to say here is "... nor
dereference the result returned by its overloaded operator->".
Just calling operator-> without dereferencing the return value
is guaranteed to be safe because the constructor is guaranteed
to initialize the internal T * to null.

Gary Duzan

unread,
Aug 19, 2002, 3:54:19 PM8/19/02
to
In article <fje79.10$7V6...@news-server.bigpond.net.au>,
Michi Henning <mi...@triodia.com> wrote:
=>"Gary Duzan" <ga...@duzan.org> wrote in message news:3d5d66fa$1...@nopics.sjc...
=>>
=>> [ ... ]
=>>
=>
=>No, that's not correct. It is true that operator T * &() is not shown
=>explicitly in section 1.9.1 of the C++ mapping. However, the mapping
=>does show the following at the end of the T_var class:
=>
=> // other conversion operators to support
=> // parameter passing
=>
=>The test then goes on to say the following:
=>
=> In addition to the member functions described above, the T_var types must
=>support
=> conversion functions that allow them to fully support the parameter passing
=>modes
=> shown in “Basic Argument and Result Passing” on page 1-105. The form of
=>these
=> conversion functions is not specified so as to allow different
=>implementations, but the
=> conversions must be automatic (i.e., they must require no explicit
=>application code to
=> invoke them).
=>
=>For sequences, inout parameters are passed as T * & (according to
=>Table 1-3).

You're in the wrong column: inout is T &. out is T * &. However,
from the verbiage at the top of section 1.22.1, it is actually a
T_out. omniidl generates a T_out parameter and provides a
T_out::T_out(T_var&), as specified in section 1.9.2, which satisfies
the parameter passing requirement.

###########################################################################
typedef sequence<long> longseq;

interface TestInt {

void op(out longseq l);
longseq op2();
void op3(inout longseq l);
};
###########################################################################
// Signatures of methods in generated stub class

void op(longseq_out l);
longseq* op2();
void op3(longseq& l);
###########################################################################
class longseq_out {
public:
typedef longseq T;
typedef longseq_var T_var;

inline longseq_out(T*& s) : _data(s) { _data = 0; }
inline longseq_out(T_var& s)
: _data(s._pd_seq) { s = (T*) 0; }
inline longseq_out(const longseq_out& s) : _data(s._data) {}
inline longseq_out& operator = (const longseq_out& s) {
_data = s._data;
return *this;
} inline longseq_out& operator = (T* s) {
_data = s;
return *this;
}
inline operator T*&() { return _data; }
inline T*& ptr() { return _data; }
inline T* operator->() { return _data; }

inline CORBA::Long& operator [] (_CORBA_ULong i) {
return (*_data)[i];
}

T*& _data;

private:
longseq_out();
longseq_out& operator=(const T_var&);
};
###########################################################################

=>> =>In any case it seems that the trick with the operator-> is a more
=>> =>general solution so you 'd better use that.
=>>
=>> That's a much better idea. However, it is still not guaranteed
=>> to work since, "Compliant applications may not attempt to convert
=>> a T_var created with the default constructor into a T* nor use its
=>> overloaded operator-> without first assigning to it a valid T* or
=>> another valid T_var." [section 1.9.1] Practically speaking, I
=>> imagine it will work in most implementations. YMMV.
=>
=>What the mapping really meant to say here is "... nor
=>dereference the result returned by its overloaded operator->".
=>Just calling operator-> without dereferencing the return value
=>is guaranteed to be safe because the constructor is guaranteed
=>to initialize the internal T * to null.

I just call 'em like I see 'em...

Michi Henning

unread,
Aug 19, 2002, 5:37:43 PM8/19/02
to
"Gary Duzan" <ga...@duzan.org> wrote in message news:3d614...@nopics.sjc...

> In article <fje79.10$7V6...@news-server.bigpond.net.au>,
> Michi Henning <mi...@triodia.com> wrote:
> =>
> =>For sequences, inout parameters are passed as T * & (according to
> =>Table 1-3).
>
> You're in the wrong column: inout is T &. out is T * &.

Oops, yes, of course.

> However,
> from the verbiage at the top of section 1.22.1, it is actually a
> T_out. omniidl generates a T_out parameter and provides a
> T_out::T_out(T_var&), as specified in section 1.9.2, which satisfies
> the parameter passing requirement.

Right.

> =>> =>In any case it seems that the trick with the operator-> is a more
> =>> =>general solution so you 'd better use that.
> =>>
> =>> That's a much better idea. However, it is still not guaranteed
> =>> to work since, "Compliant applications may not attempt to convert
> =>> a T_var created with the default constructor into a T* nor use its
> =>> overloaded operator-> without first assigning to it a valid T* or
> =>> another valid T_var." [section 1.9.1] Practically speaking, I
> =>> imagine it will work in most implementations. YMMV.
> =>
> =>What the mapping really meant to say here is "... nor
> =>dereference the result returned by its overloaded operator->".
> =>Just calling operator-> without dereferencing the return value
> =>is guaranteed to be safe because the constructor is guaranteed
> =>to initialize the internal T * to null.
>
> I just call 'em like I see 'em...

Yes -- taking the words literally, you can't call operator->() on a
default-constructed T_var. But there is no reason why this wouldn't
work because the T_var is initialized to null by the constructor --
the only case in which this would fail is if operator->() itself would
dereference the pointer, which it isn't going to do.

Gary Duzan

unread,
Aug 20, 2002, 12:21:07 PM8/20/02
to
In article <Hyd89.11974$7V6....@news-server.bigpond.net.au>,
Michi Henning <mi...@triodia.com> wrote:
=>"Gary Duzan" <ga...@duzan.org> wrote in message news:3d614...@nopics.sjc...
=> =>> Someone else (I've lost who) wrote:
=>> =>> =>In any case it seems that the trick with the operator-> is a more
=>> =>> =>general solution so you 'd better use that.

=>> =>>
=>> =>> That's a much better idea. However, it is still not guaranteed
=>> =>> to work since, "Compliant applications may not attempt to convert
=>> =>> a T_var created with the default constructor into a T* nor use its
=>> =>> overloaded operator-> without first assigning to it a valid T* or
=>> =>> another valid T_var." [section 1.9.1] Practically speaking, I
=>> =>> imagine it will work in most implementations. YMMV.

=>> =>
=>> =>What the mapping really meant to say here is "... nor
=>> =>dereference the result returned by its overloaded operator->".
=>> =>Just calling operator-> without dereferencing the return value
=>> =>is guaranteed to be safe because the constructor is guaranteed
=>> =>to initialize the internal T * to null.
=>>
=>> I just call 'em like I see 'em...
=>
=>Yes -- taking the words literally, you can't call operator->() on a
=>default-constructed T_var. But there is no reason why this wouldn't
=>work because the T_var is initialized to null by the constructor --
=>the only case in which this would fail is if operator->() itself would
=>dereference the pointer, which it isn't going to do.

Until some maniacal (but spec-compliant) implementor adds an
"initialized" flag to every T_var for "safety" and throws an
exception/aborts if operator->() is called without it being set. :-)

Jonathan Biggar

unread,
Aug 20, 2002, 1:51:52 PM8/20/02
to
Gary Duzan wrote:
> =>Yes -- taking the words literally, you can't call operator->() on a
> =>default-constructed T_var. But there is no reason why this wouldn't
> =>work because the T_var is initialized to null by the constructor --
> =>the only case in which this would fail is if operator->() itself would
> =>dereference the pointer, which it isn't going to do.
>
> Until some maniacal (but spec-compliant) implementor adds an
> "initialized" flag to every T_var for "safety" and throws an
> exception/aborts if operator->() is called without it being set. :-)

Who needs an extra flag? Just throw an exception if the pointer is null
when operator->() is called. :)

--
Jon Biggar
Floorboard Software
j...@floorboard.com
j...@biggar.org

Gary Duzan

unread,
Aug 20, 2002, 2:48:22 PM8/20/02
to
In article <3D6281B0...@floorboard.com>,
Jonathan Biggar <j...@floorboard.com> wrote:
=>Gary Duzan wrote:
=>> =>Yes -- taking the words literally, you can't call operator->() on a
=>> =>default-constructed T_var. But there is no reason why this wouldn't
=>> =>work because the T_var is initialized to null by the constructor --
=>> =>the only case in which this would fail is if operator->() itself would
=>> =>dereference the pointer, which it isn't going to do.
=>>
=>> Until some maniacal (but spec-compliant) implementor adds an
=>> "initialized" flag to every T_var for "safety" and throws an
=>> exception/aborts if operator->() is called without it being set. :-)
=>
=>Who needs an extra flag? Just throw an exception if the pointer is null
=>when operator->() is called. :)

That's true. I was thinking that the given implementor might
want to detect the difference between the uninitialized case and
the case where a user fed the T_var a null T*, but the spec requires
the T_var to be assigned a "valid T*" for operator->() to work, so
our hypothetical spec-hugging maniac could just check for null. :-)

Dirk Thomalla

unread,
Aug 20, 2002, 3:45:17 PM8/20/02
to
ga...@duzan.org (Gary Duzan) wrote:

> Until some maniacal (but spec-compliant) implementor adds an
> "initialized" flag to every T_var for "safety" and throws an
> exception/aborts if operator->() is called without it being set. :-)

If someone does so - why does she not ask for a method to test the
initialization state of the _var ...


--
- Dirk
http://www.srx6.de/dirk/

Michi Henning

unread,
Aug 20, 2002, 5:26:39 PM8/20/02
to

"Gary Duzan" <ga...@duzan.org> wrote in message news:3d626...@nopics.sjc...

As Jon says, the maniac can just test for null and throw ;-)

I've opened a defect against the C++ mapping to have the wording
in the spec updated to permit calling operator->() on an uninitialized
_var. Hopefully, that change will be voted up, so can feel safe
calling operator->() to test whether a _var is initialized.

0 new messages