Topic: Scope of friend declarations


Author: "Roger Orr" <rogero@howzatt.demon.co.uk>
Date: Sun, 16 Sep 2001 00:24:51 GMT
Raw View
Fedor G. Pikus wrote in message <3BA0EE06.40B682DF@mentorg.com>...
>I've ran into a problem where the change in the standard leads to very
>hard to find bugs
>in the code, and no warnings to help detect them.
[snip]
>class A
>{
>  private:
>  void* allocate( size_t s );
>    .... other stuff ....
>  public:
>  friend void* operator new( size_t s, A* p ) { return p->allocate( s );
>}
>
>int main()
>{
>  A a;
>  int i = new(&a) int;
>   ....
[snip]
> Operator new
>in main will be resolved to placement new, because A* will be implicitly
>converted to void*, and there is
>void* operator new( size_t s, void* p ) { return p; } defined in new.h.
>Now all calls to new(&a) will compile just fine, and all objects will be
>constructed in memory pointed to by &a.
>Seems like a good way to break old code.
>Aside from hand-checking every operator new, is there a way to detect
>this problem, make it so the first example does not compile anymore?

If you were to change the prototype to take A by reference:
 operator new( size_t s, A& p ) { return p.allocate(s); }

then it would be called by:
  int * i = new(a) int;

and the parameter will no longer match void* in a standards conforming
compiler..

In fact your current code already has the same problem -

#include <new>
class A;

void fred( A * pa )
{
   int *i = new(pa) int;
}

would call the standard placement new...

Roger Orr
--
MVP in C++ for www.brainbench.com


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Roger Orr" <rogero@howzatt.demon.co.uk>
Date: Sun, 16 Sep 2001 16:41:11 GMT
Raw View
Fedor G. Pikus wrote in message <3BA0EE06.40B682DF@mentorg.com>...
[snip]
>Aside from hand-checking every operator new, is there a way to detect
>this problem, make it so the first example does not compile anymore?


If I understand your question you wish to get a compiler error on
int * i = new( &a ) int;

You can use multiple inheritance to get this:-

#include <new>

class PROB {};

class P1 : public PROB {};
class P2 : public PROB {};

class A : public P1, public P2
{
public:
  friend void *operator new( size_t t, PROB *p );
};

int main()
{
   A a;
   int* i = new(&a) int;
   return 0;
}

This call to new now fails - ambiguous conversions from A* to PROB*

Roger Orr
--
MVP in C++ for www.brainbench.com


---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Fedor G. Pikus" <fedor_pikus@mentorg.com>
Date: Thu, 13 Sep 2001 17:37:27 GMT
Raw View
I've ran into a problem where the change in the standard leads to very
hard to find bugs
in the code, and no warnings to help detect them.
I'm curious why the change was enacted, and if someone can suggest a way
to automatically detect these problems.
Here is the problem. Let's say I have this program:

.... includes ...
class A
{
  private:
  void* allocate( size_t s );
    .... other stuff ....
  public:
  friend void* operator new( size_t s, A* p ) { return p->allocate( s );
}
};

int main()
{
  A a;
  int i = new(&a) int;
   ....
}

The friend declaration in class A used to create operator new in the
GLOBAL scope, i.e. it
created an implicit declaration above class A. Now, according to the new
standard, this implicit
forward declaration is not done. The correct way to declare and define
this operator new now is:

.... includes ....
class A;
void* operator new( size_t s, A* p );
class A
{
  private:
  void* allocate( size_t s );
    .... other stuff ....
  public:
  friend void* operator new( size_t s, A* p );
};
void* operator new( size_t s, A* p ) { return p->allocate( s ); };

int main()
{
  A a;
  int i = new(&a) int;
   ....
}

Instead of 1 declaration I now have 4, but that's not the worst of it.
Consider what happens
if I compile the first example on a standard-complying compiler: my
friend operator new will
still compile, only it will not appear in the global scope. Operator new
in main will be resolved to placement new, because A* will be implicitly
converted to void*, and there is
void* operator new( size_t s, void* p ) { return p; } defined in new.h.
Now all calls to new(&a) will compile just fine, and all objects will be
constructed in memory pointed to by &a.
Seems like a good way to break old code.
Aside from hand-checking every operator new, is there a way to detect
this problem, make it so the first example does not compile anymore?

Thanks,
Fedor
--
                                  Fedor G. Pikus
http://www.speakeasy.org/~pikus/

Mentor Graphics Corporation         | Phone: (503) 685-4857
8405 SW Boeckman Road               | FAX:   (503) 685-1239
Wilsonville, Oregon 97070           |

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Thu, 13 Sep 2001 22:37:57 GMT
Raw View
"Fedor G. Pikus" <fedor_pikus@mentorg.com> writes:

[...]

| Instead of 1 declaration I now have 4, but that's not the worst of it.

Actually, you have just two declarations: one for the friend
declacration and one for the definition.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 13 Sep 2001 22:37:46 GMT
Raw View
In article <3BA0EE06.40B682DF@mentorg.com>, Fedor G. Pikus
<fedor_pikus@mentorg.com> writes
>I've ran into a problem where the change in the standard leads to very
>hard to find bugs
>in the code, and no warnings to help detect them.
>I'm curious why the change was enacted, and if someone can suggest a way
>to automatically detect these problems.
>Here is the problem. Let's say I have this program:
>
>.... includes ...
>class A
>{
>  private:
>  void* allocate( size_t s );
>    .... other stuff ....
>  public:
>  friend void* operator new( size_t s, A* p ) { return p->allocate( s );
>}
>};
>
>int main()
>{
>  A a;
>  int i = new(&a) int;
>   ....
>}

IIRC

The problem was that template classes were injecting names into the
enclosing scope with sometimes surprising results so a more precise
requirement was made. However one of those requirements was as a result
of namespaces where any unqualified names were injected into the
enclosing namespace. There is more to it, but that will do for this
case.

Quite separately after considerable consideration of potential problems
it was decided that operator new and delete could only be overloaded at
either class or at global scope. The consequences of allowing overloads
at namespace scope were considered too potentially dangerous and with no
real benefit.

What I am puzzled by is what you are seeking to achieve with your code.


Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of Spetember 11 2001.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]