Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #11772 > unrolled thread

Any way to detect the absense of virtual destructor in base class?

Started byQi <no@no.no>
First post2011-11-24 17:20 +0800
Last post2011-11-26 11:32 +1300
Articles 17 — 10 participants

Back to article view | Back to comp.lang.c++


Contents

  Any way to detect the absense of virtual destructor in base class? Qi <no@no.no> - 2011-11-24 17:20 +0800
    Re: Any way to detect the absense of virtual destructor in base class? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2011-11-24 10:35 +0100
      Re: Any way to detect the absense of virtual destructor in base class? Qi <no@no.com> - 2011-11-24 21:05 +0800
      Re: Any way to detect the absense of virtual destructor in base class? Juha Nieminen <nospam@thanks.invalid> - 2011-11-25 18:30 +0000
        Re: Any way to detect the absense of virtual destructor in base class? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2011-11-25 22:25 +0100
          Re: Any way to detect the absense of virtual destructor in base class? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2011-11-25 22:40 +0100
          Re: Any way to detect the absense of virtual destructor in base class? Juha Nieminen <nospam@thanks.invalid> - 2011-11-25 22:30 +0000
            Re: Any way to detect the absense of virtual destructor in base class? "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2011-11-26 01:36 +0100
              Re: Any way to detect the absense of virtual destructor in base class? Juha Nieminen <nospam@thanks.invalid> - 2011-11-26 12:16 +0000
    Re: Any way to detect the absense of virtual destructor in base class? Vladimir Jovic <vladaspams@gmail.com> - 2011-11-24 10:45 +0100
      Re: Any way to detect the absense of virtual destructor in base class? Qi <no@no.com> - 2011-11-24 21:07 +0800
    Re: Any way to detect the absense of virtual destructor in base class? SG <s.gesemann@gmail.com> - 2011-11-24 04:50 -0800
      Re: Any way to detect the absense of virtual destructor in base class? Qi <no@no.com> - 2011-11-24 21:04 +0800
        Re: Any way to detect the absense of virtual destructor in base class? Marc <marc.glisse@gmail.com> - 2011-11-24 16:12 +0000
    Re: Any way to detect the absense of virtual destructor in base class? Lee Steven <steven.mtl@gmail.com> - 2011-11-25 06:55 -0800
    Re: Any way to detect the absense of virtual destructor in base class? jgk@panix.com (Joe keane) - 2011-11-25 22:21 +0000
      Re: Any way to detect the absense of virtual destructor in base class? Ian Collins <ian-news@hotmail.com> - 2011-11-26 11:32 +1300

#11772 — Any way to detect the absense of virtual destructor in base class?

FromQi <no@no.no>
Date2011-11-24 17:20 +0800
SubjectAny way to detect the absense of virtual destructor in base class?
Message-ID<jal28n$gpu$1@speranza.aioe.org>
The full question:
Any portable and standard way to detect the absence of virtual
destructor in base class?

Boost has some type traits for that, but they are intrinsic and rely
on the compilers internal implementation.

Here is some sample code,

class A {
// no virtual destructor
};

class B : public A {
// some data here, whatever
};

A * a = new B;
delete a;

If B has virtual destructor, the behavior of "delete a" is UB. (I
spent half an hour on this issue).
If B has no virtual dtor, memory leak!

So the ideal way is, whenever newing a B like that, a static assert
failure or runtime failure is thrown to indicate A needs a virtual dtor.

Is it possible?
I doubt that, but it's quite annoying to debug that problem in case
I forget to give A a virtual dtor.

If it's impossible, any suggestion on how to avoid forgetting give
base class a virtual dtor?


Thanks


-- 
WQ

[toc] | [next] | [standalone]


#11773

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2011-11-24 10:35 +0100
Message-ID<jal34c$2k7$1@dont-email.me>
In reply to#11772
On 24.11.2011 10:20, Qi wrote:
> The full question:
> Any portable and standard way to detect the absence of virtual
> destructor in base class?
>
> Boost has some type traits for that, but they are intrinsic and rely
> on the compilers internal implementation.
>
> Here is some sample code,
>
> class A {
> // no virtual destructor
> };
>
> class B : public A {
> // some data here, whatever
> };
>
> A * a = new B;
> delete a;
>
> If B has virtual destructor, the behavior of "delete a" is UB. (I
> spent half an hour on this issue).
> If B has no virtual dtor, memory leak!
>
> So the ideal way is, whenever newing a B like that, a static assert
> failure or runtime failure is thrown to indicate A needs a virtual dtor.
>
> Is it possible?
> I doubt that, but it's quite annoying to debug that problem in case
> I forget to give A a virtual dtor.
>
> If it's impossible, any suggestion on how to avoid forgetting give
> base class a virtual dtor?

Why are you using a raw pointer?

Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.

These smart pointers remember the proper derived class destruction to 
use, freeing you having to have a virtual destructor.


Cheers & hth.,

- Alf

[toc] | [prev] | [next] | [standalone]


#11780

FromQi <no@no.com>
Date2011-11-24 21:05 +0800
Message-ID<jalfnq$lb4$2@speranza.aioe.org>
In reply to#11773
On 2011-11-24 17:35, Alf P. Steinbach wrote:
>
> Why are you using a raw pointer?
>
> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
>
> These smart pointers remember the proper derived class destruction to
> use, freeing you having to have a virtual destructor.

I'm a fan of scoped pointer (though not fan of shared pointer).
But raw pointer is still quite useful to me.


-- 
WQ

[toc] | [prev] | [next] | [standalone]


#11823

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-11-25 18:30 +0000
Message-ID<4ecfdede$0$4348$7b1e8fa0@news.nbl.fi>
In reply to#11773
Alf P. Steinbach <alf.p.steinbach+usenet@gmail.com> wrote:
> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
> 
> These smart pointers remember the proper derived class destruction to 
> use, freeing you having to have a virtual destructor.

  How exactly do they achieve that? If I do, for example, this:

    std::unique_ptr<Base*> ptr = new Derived;

then how exactly is 'ptr' able to deduce the derived class destructor in
order to directly call it when it disposes of the object?

  (And where would it store it anyways? I thought the whole idea with
std::unique_ptr is that its size is that of one pointer, hence making
it as efficient as a raw pointer.)

  I wonder if you are being confused by shared_ptr (and possible other
smart pointers) being able to destroy an object even if they only see
a class declaration (rather than a definition), as long as the class was
fully declared at the point of construction of the pointer. (IOW the class
doesn't need to be fully declared at the place of destruction.) That's not
the same thing as a base-class type smart pointer being able to deduce
the derived-class type destructor.

[toc] | [prev] | [next] | [standalone]


#11824

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2011-11-25 22:25 +0100
Message-ID<jap151$5an$1@dont-email.me>
In reply to#11823
On 25.11.2011 19:30, Juha Nieminen wrote:
> Alf P. Steinbach<alf.p.steinbach+usenet@gmail.com>  wrote:
>> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
>>
>> These smart pointers remember the proper derived class destruction to
>> use, freeing you having to have a virtual destructor.
>
>    How exactly do they achieve that? If I do, for example, this:
>
>      std::unique_ptr<Base*>  ptr = new Derived;
>
> then how exactly is 'ptr' able to deduce the derived class destructor in
> order to directly call it when it disposes of the object?
>
>    (And where would it store it anyways? I thought the whole idea with
> std::unique_ptr is that its size is that of one pointer, hence making
> it as efficient as a raw pointer.)
>
>    I wonder if you are being confused by shared_ptr (and possible other
> smart pointers) being able to destroy an object even if they only see
> a class declaration (rather than a definition), as long as the class was
> fully declared at the point of construction of the pointer. (IOW the class
> doesn't need to be fully declared at the place of destruction.) That's not
> the same thing as a base-class type smart pointer being able to deduce
> the derived-class type destructor.

I'm looking at N3290, which I believe is identical to the final standard.

And there std::unique_ptr stores a deleter, which can be function object 
or a function pointer or whatever, specified in constructor call.

Essentially it's the same idea as for shared_ptr's deleter except that 
that unique_ptr doesn't use templating to infer the real type of the 
object pointer it gets, so one has to write like

   unique_ptr<Base> p = unique_ptr<Derived>( new Derived );

The only trouble is, I can't get the deleter functionality to work with 
either Visual C++ 10.0 or g++ 4.4.1 in Windows, nor with g++ 4.6.1 in 
Ubuntu.

That might indicate that my understanding is wrong (in which case the 
deleter argument then seems worthless), or that unique_ptr is not fully 
implemented by these compilers, or that N3290 is not identical to C++11?


Cheers, & thanks for focusing me on that,

- Alf

[toc] | [prev] | [next] | [standalone]


#11825

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2011-11-25 22:40 +0100
Message-ID<jap21b$b3q$1@dont-email.me>
In reply to#11824
On 25.11.2011 22:25, Alf P. Steinbach wrote:
> On 25.11.2011 19:30, Juha Nieminen wrote:
>> Alf P. Steinbach<alf.p.steinbach+usenet@gmail.com> wrote:
>>> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
>>>
>>> These smart pointers remember the proper derived class destruction to
>>> use, freeing you having to have a virtual destructor.
>>
>> How exactly do they achieve that? If I do, for example, this:
>>
>> std::unique_ptr<Base*> ptr = new Derived;
>>
>> then how exactly is 'ptr' able to deduce the derived class destructor in
>> order to directly call it when it disposes of the object?
>>
>> (And where would it store it anyways? I thought the whole idea with
>> std::unique_ptr is that its size is that of one pointer, hence making
>> it as efficient as a raw pointer.)
>>
>> I wonder if you are being confused by shared_ptr (and possible other
>> smart pointers) being able to destroy an object even if they only see
>> a class declaration (rather than a definition), as long as the class was
>> fully declared at the point of construction of the pointer. (IOW the
>> class
>> doesn't need to be fully declared at the place of destruction.) That's
>> not
>> the same thing as a base-class type smart pointer being able to deduce
>> the derived-class type destructor.
>
> I'm looking at N3290, which I believe is identical to the final standard.
>
> And there std::unique_ptr stores a deleter, which can be function object
> or a function pointer or whatever, specified in constructor call.
>
> Essentially it's the same idea as for shared_ptr's deleter except that
> that unique_ptr doesn't use templating to infer the real type of the
> object pointer it gets, so one has to write like
>
> unique_ptr<Base> p = unique_ptr<Derived>( new Derived );
>
> The only trouble is, I can't get the deleter functionality to work with
> either Visual C++ 10.0 or g++ 4.4.1 in Windows, nor with g++ 4.6.1 in
> Ubuntu.
>
> That might indicate that my understanding is wrong (in which case the
> deleter argument then seems worthless), or that unique_ptr is not fully
> implemented by these compilers, or that N3290 is not identical to C++11?

I asked it also on SO,

http://stackoverflow.com/questions/8274451/well-how-does-the-custom-deleter-of-stdunique-ptr-work

Cheers,

- Alf

[toc] | [prev] | [next] | [standalone]


#11827

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-11-25 22:30 +0000
Message-ID<4ed0171b$0$2769$7b1e8fa0@news.nbl.fi>
In reply to#11824
Alf P. Steinbach <alf.p.steinbach+usenet@gmail.com> wrote:
> I'm looking at N3290, which I believe is identical to the final standard.
> 
> And there std::unique_ptr stores a deleter, which can be function object 
> or a function pointer or whatever, specified in constructor call.

  If std::unique_ptr is indeed specified to store a pointer to a deleter
function (or a deleter object), then it's a bit disappointing.

  When I read that std::unique_ptr would be a better replacement for
std::auto_ptr, I was assuming that it's a smart pointer that is as
efficient as a raw pointer (at least in terms of size), which destroys
the managed object automatically (the advantage over std::auto_ptr being
that it's safe to use in data containers such as std::vector, which may
move its elements around when reallocating, inserting in the middle or
eg. sorting).

  However, if std::unique_ptr is (at least) the size of *two* pointers,
it immediately becomes inferior to a raw pointer in terms of efficiency.
While in many/most cases that doesn't matter, it's a bummer in situations
where it would.

  I understand the advantage of having a pointer to a deleter in the smart
pointer object: It allows safely deleting an object even in contexts where
the class has only been declared (rather than defined), plus some other
situations (such as using a specialized deleter for the managed object).
However, these situations are quite unusual in practice, and I find it
questionable why one has to pay for something that isn't used, which goes
against one of the core principles of C++. (After all, this principle is
the very reason why eg. classes do not have virtual tables by default,
but only if there specifically are virtual functions. You don't have to
pay for what you don't use.)

  Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
using some kind of empty base class optimization trick) in cases where
no deleter is explicitly specified?

[toc] | [prev] | [next] | [standalone]


#11832

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2011-11-26 01:36 +0100
Message-ID<japca2$bcp$1@dont-email.me>
In reply to#11827
On 25.11.2011 23:30, Juha Nieminen wrote:
> Alf P. Steinbach<alf.p.steinbach+usenet@gmail.com>  wrote:
>> I'm looking at N3290, which I believe is identical to the final standard.
>>
>> And there std::unique_ptr stores a deleter, which can be function object
>> or a function pointer or whatever, specified in constructor call.
>
>    If std::unique_ptr is indeed specified to store a pointer to a deleter
> function (or a deleter object), then it's a bit disappointing.
>
>    When I read that std::unique_ptr would be a better replacement for
> std::auto_ptr, I was assuming that it's a smart pointer that is as
> efficient as a raw pointer (at least in terms of size), which destroys
> the managed object automatically (the advantage over std::auto_ptr being
> that it's safe to use in data containers such as std::vector, which may
> move its elements around when reallocating, inserting in the middle or
> eg. sorting).
>
>    However, if std::unique_ptr is (at least) the size of *two* pointers,
> it immediately becomes inferior to a raw pointer in terms of efficiency.
> While in many/most cases that doesn't matter, it's a bummer in situations
> where it would.

Yes, that is the case, sorry.

>
>    I understand the advantage of having a pointer to a deleter in the smart
> pointer object: It allows safely deleting an object even in contexts where
> the class has only been declared (rather than defined), plus some other
> situations (such as using a specialized deleter for the managed object).
> However, these situations are quite unusual in practice, and I find it
> questionable why one has to pay for something that isn't used, which goes
> against one of the core principles of C++. (After all, this principle is
> the very reason why eg. classes do not have virtual tables by default,
> but only if there specifically are virtual functions. You don't have to
> pay for what you don't use.)

I agree.


>    Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
> using some kind of empty base class optimization trick) in cases where
> no deleter is explicitly specified?

I'm not sure.

Anyway I misunderstood the deleter thing. As someone pointed out on SO, 
with unique_ptr the deleter type is a template argument for the /type/. 
And it doesn't work (directly) for the usage where you allocate as 
derived and delete as base, without virtual destructor.

However, I managed to browbeat the unique_ptr functionality into doing 
that, by applying a little type erasure: :-)


<code>
#include <iostream>
#include <memory>           // std::unique_ptr
#include <functional>       // function
#include <utility>          // move
#include <string>
using namespace std;

class Base
{
public:
     Base() { cout << "Base:<init>" << endl; }
     ~Base() { cout << "Base::<destroy>" << endl; }
};

class Derived
     : public Base
{
public:
     Derived() { cout << "Derived::<init>" << endl; }
     ~Derived() { cout << "Derived::<destroy>" << endl; }
};

class BoundDeleter
{
private:
     typedef void (*DeleteFunc)( void* p );

     DeleteFunc  deleteFunc_;
     void*       pObject_;

     template< class Type >
     static void deleteFuncImpl( void* p )
     {
         delete static_cast< Type* >( p );
     }

public:
     template< class Type >
     BoundDeleter( Type* pObject )
         : deleteFunc_( &deleteFuncImpl< Type > )
         , pObject_( pObject )
     {}

     BoundDeleter( BoundDeleter&& other )
         : deleteFunc_( move( other.deleteFunc_ ) )
         , pObject_( move( other.pObject_ ) )
     {}

     void operator() (void*) const
     {
         deleteFunc_( pObject_ );
     }
};

template< class Type >
class SafeCleanupUniquePtr
     : public unique_ptr< Type, BoundDeleter >
{
public:
     typedef unique_ptr< Type, BoundDeleter >    Base;

     template< class ActualType >
     SafeCleanupUniquePtr( ActualType* p )
         : Base( p, BoundDeleter( p ) )
     {}

     template< class Other >
     SafeCleanupUniquePtr( SafeCleanupUniquePtr< Other >&& other )
         : Base( move( other ) )
     {}
};

int main()
{
     SafeCleanupUniquePtr< Base >  p( new Derived );
}
</code>


Cheers,

- Alf

[toc] | [prev] | [next] | [standalone]


#11849

FromJuha Nieminen <nospam@thanks.invalid>
Date2011-11-26 12:16 +0000
Message-ID<4ed0d898$0$2827$7b1e8fa0@news.nbl.fi>
In reply to#11832
Alf P. Steinbach <alf.p.steinbach+usenet@gmail.com> wrote:
>>    Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
>> using some kind of empty base class optimization trick) in cases where
>> no deleter is explicitly specified?
> 
> I'm not sure.

  I did what I should have done earlier, and tested it. In a 64-bit system
using gcc 4.6.1 both sizeof(int*) and sizeof(std::unique_ptr<int>) are 8,
so I suppose it is smart enough to avoid reserving space for an unneeded
deleter pointer.

  That means I was too hasty to be disappointed with std::unique_ptr.

[toc] | [prev] | [next] | [standalone]


#11774

FromVladimir Jovic <vladaspams@gmail.com>
Date2011-11-24 10:45 +0100
Message-ID<jal3nh$ob6$1@news.albasani.net>
In reply to#11772
On 24/11/11 10:20, Qi wrote:
> The full question:
> Any portable and standard way to detect the absence of virtual
> destructor in base class?
>
> Boost has some type traits for that, but they are intrinsic and rely
> on the compilers internal implementation.
>
> Here is some sample code,
>
> class A {
> // no virtual destructor
> };
>
> class B : public A {
> // some data here, whatever
> };
>
> A * a = new B;
> delete a;
>
> If B has virtual destructor, the behavior of "delete a" is UB. (I
> spent half an hour on this issue).
> If B has no virtual dtor, memory leak!
>
> So the ideal way is, whenever newing a B like that, a static assert
> failure or runtime failure is thrown to indicate A needs a virtual dtor.
>
> Is it possible?
> I doubt that, but it's quite annoying to debug that problem in case
> I forget to give A a virtual dtor.
>
> If it's impossible, any suggestion on how to avoid forgetting give
> base class a virtual dtor?

That check would be more complex then adding the "virtual" keyword to 
the destructor of the base class.

Anyway, here you are:

#include <boost/type_traits/has_virtual_destructor.hpp>
struct a
{
     virtual ~a(){}
};
struct b
{
     virtual ~b(){}
};

// ok
static_assert( boost::has_virtual_destructor<a>::value, "no virt 
destructor" );
// error
static_assert( boost::has_virtual_destructor<b>::value, "no virt 
destructor" );

int main()
{
}

[toc] | [prev] | [next] | [standalone]


#11781

FromQi <no@no.com>
Date2011-11-24 21:07 +0800
Message-ID<jalfqs$lb4$3@speranza.aioe.org>
In reply to#11774
On 2011-11-24 17:45, Vladimir Jovic wrote:
> // ok
> static_assert( boost::has_virtual_destructor<a>::value, "no virt
> destructor" );
> // error
> static_assert( boost::has_virtual_destructor<b>::value, "no virt
> destructor" );

That Boost trait has some assumption on the compiler dependent
object binary layout, AFAIK.
So it's neither standard nor portable.


-- 
WQ

[toc] | [prev] | [next] | [standalone]


#11778

FromSG <s.gesemann@gmail.com>
Date2011-11-24 04:50 -0800
Message-ID<73c0b260-1a76-4de9-a3ed-e272978d916e@y12g2000vba.googlegroups.com>
In reply to#11772
On 24 Nov., 10:20, Qi wrote:
> The full question:
> Any portable and standard way to detect the absence of virtual
> destructor in base class?

Since you said "standard way" and did not explicitly exclude C++2011:

  #include <type_traits>

  :::

  std::has_virtual_destructor<YourType>::value

Cheers!
SG

[toc] | [prev] | [next] | [standalone]


#11779

FromQi <no@no.com>
Date2011-11-24 21:04 +0800
Message-ID<jalfl4$lb4$1@speranza.aioe.org>
In reply to#11778
On 2011-11-24 20:50, SG wrote:
> Since you said "standard way" and did not explicitly exclude C++2011:
>
>    #include<type_traits>
>
>    :::
>
>    std::has_virtual_destructor<YourType>::value

Thanks

This, plus static assert, seems an elegant solution.

But,
1, Any equivalence in C++2003 ?
2, If not, any "standard" way to detect the compiler
supports only 03 or also supports 11? So I can have some
backward compatibility.


-- 
WQ

[toc] | [prev] | [next] | [standalone]


#11789

FromMarc <marc.glisse@gmail.com>
Date2011-11-24 16:12 +0000
Message-ID<jalqe2$av4$1@news-rocq.inria.fr>
In reply to#11779
Qi  wrote:

> 2, If not, any "standard" way to detect the compiler
> supports only 03 or also supports 11? So I can have some
> backward compatibility.

The value of the macro __cplusplus *should* do it.

[toc] | [prev] | [next] | [standalone]


#11822

FromLee Steven <steven.mtl@gmail.com>
Date2011-11-25 06:55 -0800
Message-ID<eca72684-4f61-41ae-b40d-91fe4875d5d7@p9g2000vbb.googlegroups.com>
In reply to#11772
On Nov 24, 5:20 am, Qi <n...@no.no> wrote:
> The full question:
> Any portable and standard way to detect the absence of virtual
> destructor in base class?
>
> Boost has some type traits for that, but they are intrinsic and rely
> on the compilers internal implementation.
>
> Here is some sample code,
>
> class A {
> // no virtual destructor
>
> };
>
> class B : public A {
> // some data here, whatever
>
> };
>
> A * a = new B;
> delete a;
>
> If B has virtual destructor, the behavior of "delete a" is UB. (I
> spent half an hour on this issue).
> If B has no virtual dtor, memory leak!
>
> So the ideal way is, whenever newing a B like that, a static assert
> failure or runtime failure is thrown to indicate A needs a virtual dtor.
>
> Is it possible?
> I doubt that, but it's quite annoying to debug that problem in case
> I forget to give A a virtual dtor.
>
> If it's impossible, any suggestion on how to avoid forgetting give
> base class a virtual dtor?
>
> Thanks
>
> --
> WQ

Here, I think If A has no virtual dtor, memory leak!

[toc] | [prev] | [next] | [standalone]


#11826

Fromjgk@panix.com (Joe keane)
Date2011-11-25 22:21 +0000
Message-ID<jap4ci$f3k$1@reader1.panix.com>
In reply to#11772
fire them

[toc] | [prev] | [next] | [standalone]


#11828

FromIan Collins <ian-news@hotmail.com>
Date2011-11-26 11:32 +1300
Message-ID<9jajbsF4d0U9@mid.individual.net>
In reply to#11826
On 11/26/11 11:21 AM, Joe keane wrote:
> fire them

Fire who?  There isn't a premium charged for quoting context.

-- 
Ian Collins

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web