Topic: Why's of C++ part 10? -- scope


Author: "Greg Brewer" <nospam.greg@brewer.net>
Date: 2000/02/15
Raw View
I'm only sorta back.  Still real busy but see the light of the on-coming
train.

One of the things that has been bugging me lately is the lack of control for
the scope of local objects.  There is probably a better name and if I had
more time then I would look it up.  Anyway, I'll confess that this post
isn't well thought out.  I was accessing another newsgroup and decided to
drop by here.

One of the things I like to do is use a class to ensure a resource is
released when I'm finished with it.  Something like the following

class Workspace
{
   char workspace[16], *ws;
public:
   Workspace(int sz) {if (sz <= 16) return ws=workspace;return ws=new
char[sz];}
  ~Workspace(void) {if (ws!=workspace) delete [] ws;}
 operator char *() {return ws;}
};

void DoSomething(void) {
   Workspace buffer(64);
   char *s = buffer;
   // do a bunch of stuff
   if (alldone) return;
   // do some more stuff
};

With this design, the buffer space allocated will automatically be released
when the function is exited.  The problem with it is that the following
would be legal code
void DoSomething(void) {
   char *s = Workspace(64);
   // do a bunch of stuff
   if (alldone) return;
   // do some more stuff
};

but would assign s buffer space that has gone out of scope.  Would it be
nice if I could place a modifier in the definition of Workspace that might
cause the scope to be increased to what ever the local scope is.

Similarly, coding such as
void DoSomething(void) {
   for (int i = 0; i < 8; i++)
   {
       Workspace ws;
      // ....
   }
}
would cause the ctor/dtor to be called only once instead of 8 times.

In a somewhat related note, it would be nice if one could access the
workspace allocated for a function return.  Consider the case of

Data Xyz(void) {
   // code
}

Wouldn't it be nice to be able to just directly access the space allocated
for Data instead of allocating a 2nd Data item and having to rely on the
cstor to move the item.  As it is, if Data has allocated data, one has to be
careful that the pointer address doesn't get copied and then deleted by the
dstor.  Moreover, combining the two would provide a storage space for a
function that would exist for the duration of the local scope so that

   for (int i = 0; i < 8; i++)
   {
       Xyz();
   }

Xyz could store information in Data during the nth iteration of the loop
that could be accessed in the (n+1)th iteration.

Well, I have to run.  Hopefully, I'll get a chance to see how I get shot
down.  Hope the presentation of the ideas was clear enough.  I confess that
the ideas are really half backed.  I recently wrote a function that tested
several dozen points in linked list that consisted of at least 840 nodes.
Each node has 2 pointers to additional items.  There is a many-to-one
relationship between the pointers of a node so that many -- or all -- nodes
may point to the same 2 items.  Once a pointer in a node has been tested, I
don't need to test it again.  I don't always start at the beginning or
terminate at the end.  It would have been nice if I could access some local
storage in the loop that only had the same scope as the for loop.  Of course
I handled the situation; but, the prefered solution was not available.

Greg Brewer


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 2000/02/15
Raw View
Greg Brewer wrote:
>
> I'm only sorta back.  Still real busy but see the light of the on-coming
> train.
>
> One of the things that has been bugging me lately is the lack of control for
> the scope of local objects.  There is probably a better name and if I had
> more time then I would look it up.  Anyway, I'll confess that this post
> isn't well thought out.  I was accessing another newsgroup and decided to
> drop by here.
>
> One of the things I like to do is use a class to ensure a resource is
> released when I'm finished with it.  Something like the following
>
> class Workspace
> {
>    char workspace[16], *ws;
> public:
>    Workspace(int sz) {if (sz <= 16) return ws=workspace;return ws=new
> char[sz];}

You're attempting to return a value from a constructor? The following
seems cleaner to me:

 Workspace(int sz) { ws = (sz<=16 ? workspace : new char[sz]); }

>   ~Workspace(void) {if (ws!=workspace) delete [] ws;}
>  operator char *() {return ws;}
> };
>
> void DoSomething(void) {
>    Workspace buffer(64);
>    char *s = buffer;
>    // do a bunch of stuff
>    if (alldone) return;
>    // do some more stuff
> };
>
> With this design, the buffer space allocated will automatically be released
> when the function is exited.  The problem with it is that the following
> would be legal code
> void DoSomething(void) {
>    char *s = Workspace(64);
>    // do a bunch of stuff
>    if (alldone) return;
>    // do some more stuff
> };

Yes, it would be legal code, though only as long as you never use the
value stored in s. The allocated memory it refers to can not be safely
referred to, because the temporary object that allocated that space,
also deallocated it when the temporary was destroyed, at the end of the
initialization expression.

That's one reason why std::vector<> was designed with an operator[],
rather than an operator (T*)().

....
> Similarly, coding such as
> void DoSomething(void) {
>    for (int i = 0; i < 8; i++)
>    {
>        Workspace ws;
>       // ....
>    }
> }
> would cause the ctor/dtor to be called only once instead of 8 times.

You can get the same effect by moving the 'ws' definition outside of the
for loop. If you don't want it to have a separate scope, put it in an
enclosing block:

void DoSomething(void) {
   {
        Workspace ws;
        for(int i=0; i<8; i++)
        {
            // Code which can see ws.
        }
   }
   // Other code that can't see ws.
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Greg Brewer" <nospam.greg@brewer.net>
Date: 2000/02/16
Raw View
Oops.  You are right.  As I implied in my posting, it was an off the cuff
posting.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/02/17
Raw View
Greg Brewer wrote:
>
> I'm only sorta back.  Still real busy but see the light of the on-coming
> train.
>
> One of the things that has been bugging me lately is the lack of control for
> the scope of local objects.  There is probably a better name and if I had
> more time then I would look it up.  Anyway, I'll confess that this post
> isn't well thought out.  I was accessing another newsgroup and decided to
> drop by here.
>
> One of the things I like to do is use a class to ensure a resource is
> released when I'm finished with it.  Something like the following
>
> class Workspace
> {
>    char workspace[16], *ws;
> public:
>    Workspace(int sz) {if (sz <= 16) return ws=workspace;return ws=new
> char[sz];}

You want to remove the "return" keywords here.

>   ~Workspace(void) {if (ws!=workspace) delete [] ws;}
>  operator char *() {return ws;}
> };
>
> void DoSomething(void) {
>    Workspace buffer(64);
>    char *s = buffer;
>    // do a bunch of stuff
>    if (alldone) return;
>    // do some more stuff
> };
>
> With this design, the buffer space allocated will automatically be released
> when the function is exited.  The problem with it is that the following
> would be legal code
> void DoSomething(void) {
>    char *s = Workspace(64);
>    // do a bunch of stuff
>    if (alldone) return;
>    // do some more stuff
> };
>
> but would assign s buffer space that has gone out of scope.  Would it be
> nice if I could place a modifier in the definition of Workspace that might
> cause the scope to be increased to what ever the local scope is.

What you've shown here is one danger of operator char*()
(there's a reason why std::string doesn't have it, after all).

If you want to entirely disallow getting a workspace from
temporary objects, you can do the following:

class Workspace
{
  friend char* get_ws(Workspace&);
public:
  Workspace(size_t size): ws(size<=16? workspace : new char(size) {}
  ~Workspace() { if (ws != workspace) delete ws; }
private:
  char workspace[16];
  char* ws;
};

inline char* get_ws(Workspace& w) { return w.ws; }

Now, the following is possible:

void foo()
{
  Workspace w(64);
  char* s = get_ws(w);
  // use s
  if (all_done) return;
  // do more
}

but the following will be flagged as error:

void bar()
{
  char* s = get_ws(Workspace(64));
    // error: cannot bind temporary to non-const reference
  // ...
}

>
> Similarly, coding such as
> void DoSomething(void) {
>    for (int i = 0; i < 8; i++)
>    {
>        Workspace ws;
>       // ....
>    }
> }
> would cause the ctor/dtor to be called only once instead of 8 times.

void DoSomething()
{
  {
    Workspace ws(64);
    for (int i=0; i<8; ++i)
    {
      // ....
    }
  }
}

[...]

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]