priority_queue help

S

Stephen Horne

So, I guess since it's in my constructor of the App class, out of scope
is when this class, my app shuts down?

If you declare a variable locally within a constructor, it goes out of
scope when the constructor exits.

If you declare a variable as a normal member of a class, it constructs
when an instance of the class is constructed, and it destructs when
that class instance destructs.

If you declare a variable as a global, or as a static class member, it
constructs when the app starts and destructs when the app exits.

If you want to create an instance within your App constructor, but
keep it around until your App instance destructs, you have two
choices. One is the pointer method you were already using. The
preferred alternative is a simple member - preferred because the
cleanup is assured without needing to worry about delete etc.

The only hassle with the member variable is providing the constructor
parameters to the initialiser, since you have to use something like...

class myApp
{
private:
myClass m_Member;

public:
myApp (...);
};

myApp::myApp (...) : m_Member (...) // initialiser here
{
// body of constructor doesn't run until after
}

This *can* be a severe problem, if you need to calculate the "..."
parameters within your myApp constructor. It's always possible, but
sometimes painful. One heavyweight approach for difficult cases is to
move your constructor calculations into the constructor for another
class, have an instance of that as a member of myApp, and ensure it is
initialised first so you can get the needed parameters from it.

In short, the simple member is preferred when practical, but you may
be better off sticking with the pointer.

One really evil approach is to use another type to get an
uninitialised block of memory for the field (watching out for
alignment issues), and use lots of typecasts plus placement new, and
explicit destructor calls. I should be shot for even mentioning that,
though. No-one would do this for high-level code.
 
J

James Kanze

If you declare a variable locally within a constructor, it
goes out of scope when the constructor exits.

More generally, I think the original poster needs to read up on
lifetime of object issues. Unlike the case of Java, these can
be handled automatically in C++, at least in many cases. But
until you understand the issues, you can't really start
evaluating what is most appropriate to your case.

[...]
If you want to create an instance within your App constructor,
but keep it around until your App instance destructs, you have
two choices. One is the pointer method you were already using.
The preferred alternative is a simple member - preferred
because the cleanup is assured without needing to worry about
delete etc.
The only hassle with the member variable is providing the
constructor parameters to the initialiser, since you have to
use something like...
class myApp
{
private:
myClass m_Member;
public:
myApp (...);
};
myApp::myApp (...) : m_Member (...) // initialiser here
{
// body of constructor doesn't run until after
}
This *can* be a severe problem, if you need to calculate the
"..." parameters within your myApp constructor.

Yes. Using a local function can often help, but at times, you
may end up having to leave the member default constructed, and
assigning to it (or otherwise modifying its state) later in the
constructor body.
It's always possible, but sometimes painful. One heavyweight
approach for difficult cases is to move your constructor
calculations into the constructor for another class, have an
instance of that as a member of myApp, and ensure it is
initialised first so you can get the needed parameters from
it.

That is heavyweight. If I can modify the member class, I'd
rather add a constructor to it, which can deal with the
parameters I have.
In short, the simple member is preferred when practical, but
you may be better off sticking with the pointer.

You mean as a means of allowing deferred initialization. That's
one (simple and easy to understand) way.
One really evil approach is to use another type to get an
uninitialised block of memory for the field (watching out for
alignment issues), and use lots of typecasts plus placement
new, and explicit destructor calls. I should be shot for even
mentioning that, though. No-one would do this for high-level
code.

You mean "evil" in this context, don't you. Doing this to
separate allocation from initialization has been a standard
technique for containers for as long as I can remember. Of
course, most uses today are hidden in the standard library, but
I still use it in my Fallible class---if I have no valid value,
there may be no way of constructing the object to begin with.
 
J

James Kanze

@de.bosch.com> wrote:

[...]
OK - looks like you both got me. Clearly I got that wrong.
Of course I'd never define a nested function.

You can't *define* a nested function; only declare one. As to
why the possibility is there: C compatibility. But of course,
the same issue would occur if you tried to define the object as
a global variable.
C++ doesn't support what I think of as *correct* nested
functions, therefore there's really not much point defining
functions within another function. Second, on those rare cases
where having a function with that small a scope (but no other
features associated with nested functions) was beneficial,
I've always found that every compiler chokes on it.

I've yet to see a compiler which had problems with a function
declaration with local scope. On the other hand, I've yet to
find a use for it in cleanly written code---if you need a
declaration, it's because the function was defined elsewhere.
In which case, you want the declaration in a header file, which
you certainly don't want to include inside a function.
Changing the subject a bit, but just what is going on with
language standardisation these days. Back in the day, the
remit of standards people was to formalise and standardise
*existing* *best* *practice*. Not to invent untested
code-breaking "nice" ideas and inflict them on unsuspecting
developers.

The first version of the C++ standard was somewhat an exception
to that philosophy:). And it broke a lot of existing code. On
the other hand, sometimes, some innovation is necessary. The C
standard practically redefined the preprocessor (there were at
least two wide spread, incompatible "existing practices"). And
C++ would be a lot poorer without a vector or a string class.

In this particular case, however, the problem is more that the
standard didn't to break with existing practice, which was to
allow such declarations:).
That's not about nested function prototypes for the half-baked
C++ nested functions - god knows when they were first thought
up, probably for K&R C - just other stuff that's seriously
bugging me right now.

Yes. C++ inherited its declaration syntax from C (and later
extended it); the nicest thing you can say about C's declaration
syntax is that it was an interesting experiment (which failed).
I mean, processors have had alignment issues for as long as I
can remember now. Even 16 bit processors such as the 68000 and
8086. Yet even now, 20+ years after the fact (more if you move
off the desktop), they're still thinking about it. Without
taking account of alignment issues, you simply *cannot* write
a reasonable container library, it's a trivial thing to define
a couple of features to do the job, but they're too busy.

There will be some in the next verions of the standard. In the
meantime, most of the time you need to worry about alignment,
you're dealing with dynamically allocated memory, which is
guaranteed to be sufficiently aligned for anything. In the few
other cases, you can use the template I posted recently, which
works in practice.

Of course, now that the traditional alignment problems are being
addressed... there are often good reasons in modern processors
to require stricter alignment for tables of elements than for a
single element---in some particular cases, you may even want to
align a table on a page boundary. Which means that before the
original problem is solved in practice (i.e. in the compiler
you're using), a new problem will have risen to replace it.
But when it comes to template scoping rules, they're more than
happy to invent standards that contradict what those compilers
that could actually cope with templates properly had been
doing since the mid-to-late 90s.

When the basic premise behind the rules was put forward, there
was only one compiler which implemented templates, CFront, and
it did so pretty poorly. For better or for worse, one can
consider everything to do with templates "innovation" on the
part of the committee, with no existing practice to go on.

The issue is more complex than that, of course. The fact that
there was so much innovation delayed the standard to a point
where there was existing practice, and conceivably, the
committee could have changed course and aligned itself with the
existing practice. On the other hand, the fact that there would
be two types of name lookup was clearly established in committee
papers as early as 1992, I believe, so any vendor who
implemented templates without it after that date can be
considered irresponsible. And of course, since it was obvious
that templates were still very much in flux, and far from
stabilised, it could also be argued that anyone who used them
before around 2000 was being irresponsible, or at least knew
that they'd have to seriously rework their code later.
Clearly, their priorities are screwed up. Thank god they're
part time and underfunded - can you imagine what it would be
like if they were full time?
Wonder what they're dreaming up now. Probably ways to turn C++
into bizarre Haskell hybrid, or something equally stupid. I
wouldn't even be surprised if they're planning to add garbage
collection to jump on the Java/.NET bandwagon.

The most important single issue is threading. From a practical
point of view, threading and garbage collection are essential if
the language is going to continue to be usable (independantly of
any technical arguments). From a practical point of view,
garbage collection is "existing practice", and works well.
Threading sort of, as well, although most multi-threaded
applications I've seen don't actually work.

One thing that is clear, however, is that the committee is
making considerable effort to avoid breaking existing code
(which wasn't really the case a decade ago). There'll be a lot
of new additions, but very little change in the basics.
 
S

Stephen Horne

On the other hand, the fact that there would
be two types of name lookup was clearly established in committee
papers as early as 1992, I believe, so any vendor who
implemented templates without it after that date can be
considered irresponsible.

There was no standard to go on at the time beyond widely understood
pseudo-standard, ie "what Stroustrup says". It definitely includes
templates.
And of course, since it was obvious
that templates were still very much in flux, and far from
stabilised, it could also be argued that anyone who used them
before around 2000 was being irresponsible, or at least knew
that they'd have to seriously rework their code later.

I'd blame Stroustrup. If there's anything about different lookup rules
in my (post-standardization) copy, it's well hidden, and as I said -
this was the effective definition of the standard prior to
standardization.
The most important single issue is threading. From a practical
point of view, threading and garbage collection are essential if
the language is going to continue to be usable (independantly of
any technical arguments). From a practical point of view,
garbage collection is "existing practice", and works well.

Oh dear - that was meant to be a sarcastic joke.

Garbage collection is certainly existing practice and works well -
*in* *other* *languages*. A major reason for using C++ is because you
don't get forced into using automated garbage collection.

IMO GC only makes sense when it is done by default, but there's ways
to opt out (and for systems languages, back in - see later). This can
*never* be the case in C++ for backward compatibility reasons.

That said, GC as a library works fine, or so Stroustrup says - though
I think he may have missed the whole point of GC.

One problem I had using D a couple of years ago was that you could opt
out of GC but then couldn't opt back in again. When writing a
container, you could manage the garbage yourself for the data
structure nodes, but in doing so you hid the applications contained
data (or rather anything it references) from the GC too - there was no
way to opt back in. It shouldn't be impossible to supply a
mark-all-contained-data-items function or iterator or whatever, though
certainly there's bound to be some technicalities.

I'd got pretty committed before I found this out. Ended up binning a
lot of code. Experiences like this make me very suspicious about
claims WRT GC in systems languages.
 

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

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top