"Niels Dybdahl" <ndy@fjern.detteesko-graphics.com> wrote:
[8<8<8<]
> Compilere som MSVC tillader da også at man kan bruge delete istedet
> for delete[].
Hvilken version (og hvilken definition af "tillader") ?
Det er ikke umiddelbart hvad jeg ser med V6 og V7.1, hvis man med "tillade"
forstår at det udover at oversætte (hvilket det _skal_ ifølge sprog
specifikationen) også fører til eksekvering svarende til at have skrevet
"delete []".
Med Microsoft Visual C++ .NET 2003 (V7.1) giver følgende program:
#include <iostream>
using namespace std;
class base
{
public:
base();
virtual ~base();
private:
base(const base&);
base& operator=(const base&);
};
base::base()
{
cout << "base::base( this:" << this << ")" << endl;
}
base:
base()
{
cout << "base:
base(this:" << this << ")" << endl;
}
int main()
{
delete new base[10];
}
i debug build følgede fejl-dialog:
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: F:\cpp\fnyt\Debug\fnyt.exe
File: dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
---------------------------
Abort Retry Ignore
---------------------------
Noget tilsvarende ser jeg med Microsoft Visual C++ V6.0 SP4
I release giver det følgende output:
<output>
base::base( this:00371EDC)
base::base( this:00371EE0)
base::base( this:00371EE4)
base::base( this:00371EE8)
base::base( this:00371EEC)
base::base( this:00371EF0)
base::base( this:00371EF4)
base::base( this:00371EF8)
base::base( this:00371EFC)
base::base( this:00371F00)
base:
base(this:00371EDC)
</output>
og hvis man kører det fra ide'et bliver det suppleret med "Unhandled
exception at 0x77f75a58 in fnyt.exe: User breakpoint."
Bemærk kun een destructor bliver kaldt.
En anden "sjov" måde at lave "undefined behaviour" i forbindelse med
frigivelse af arrays er ved at benytte en peger til en basis-klasse (C++
Standard §5.3.5 (og §16.2)):
#include
using namespace std;
class base
{
public:
base();
virtual ~base();
private:
base(const base&);
base& operator=(const base&);
};
class derived : public base
{
public:
derived();
virtual ~derived();
private:
char take_up_some_space[1024];
private:
derived(const derived&);
derived& operator=(const derived&);
};
base::base()
{
cout << "base::base( this:" << this << ")" << endl;
}
base:
base()
{
cout << "base:
base(this:" << this << ")" << endl;
}
derived::derived()
{
cout << "derived::derived( this:" << this << ")" << endl;
}
derived:
derived()
{
cout << "derived:
derived(this:" << this << ")" << endl;
}
int main()
{
base* b = new derived[10];
delete [] b; // undefined behaviour
}
Med Microsoft Visual C++ .NET 2003 giver det et fornuftigt resultat
base::base( this:00373C34)
derived::derived( this:00373C34)
base::base( this:00374038)
derived::derived( this:00374038)
base::base( this:0037443C)
derived::derived( this:0037443C)
base::base( this:00374840)
derived::derived( this:00374840)
base::base( this:00374C44)
derived::derived( this:00374C44)
base::base( this:00375048)
derived::derived( this:00375048)
base::base( this:0037544C)
derived::derived( this:0037544C)
base::base( this:00375850)
derived::derived( this:00375850)
base::base( this:00375C54)
derived::derived( this:00375C54)
base::base( this:00376058)
derived::derived( this:00376058)
derived:
derived(this:00376058)
base:
base(this:00376058)
derived:
derived(this:00375C54)
base:
base(this:00375C54)
derived:
derived(this:00375850)
base:
base(this:00375850)
derived:
derived(this:0037544C)
base:
base(this:0037544C)
derived:
derived(this:00375048)
base:
base(this:00375048)
derived:
derived(this:00374C44)
base:
base(this:00374C44)
derived:
derived(this:00374840)
base:
base(this:00374840)
derived:
derived(this:0037443C)
base:
base(this:0037443C)
derived:
derived(this:00374038)
base:
base(this:00374038)
derived:
derived(this:00373C34)
base:
base(this:00373C34)
Hvorimod Intel C++ V8.0 for MS-Windows og Borland C++Builder V6.0 Patch 4
giver et underligt, men fuldt lovligt, resultat
base::base( this:00373C34)
derived::derived( this:00373C34)
base::base( this:00374038)
derived::derived( this:00374038)
base::base( this:0037443C)
derived::derived( this:0037443C)
base::base( this:00374840)
derived::derived( this:00374840)
base::base( this:00374C44)
derived::derived( this:00374C44)
base::base( this:00375048)
derived::derived( this:00375048)
base::base( this:0037544C)
derived::derived( this:0037544C)
base::base( this:00375850)
derived::derived( this:00375850)
base::base( this:00375C54)
derived::derived( this:00375C54)
base::base( this:00376058)
derived::derived( this:00376058)
base:
base(this:00373C58)
base:
base(this:00373C54)
base:
base(this:00373C50)
base:
base(this:00373C4C)
base:
base(this:00373C48)
base:
base(this:00373C44)
base:
base(this:00373C40)
base:
base(this:00373C3C)
base:
base(this:00373C38)
base:
base(this:00373C34)
base::base( this:10054020)
derived::derived( this:10054020)
base::base( this:10055048)
derived::derived( this:10055048)
base::base( this:10056076)
derived::derived( this:10056076)
base::base( this:10057104)
derived::derived( this:10057104)
base::base( this:10058132)
derived::derived( this:10058132)
base::base( this:10059160)
derived::derived( this:10059160)
base::base( this:10060188)
derived::derived( this:10060188)
base::base( this:10061216)
derived::derived( this:10061216)
base::base( this:10062244)
derived::derived( this:10062244)
base::base( this:10063272)
derived::derived( this:10063272)
base:
base(this:10054056)
base:
base(this:10054052)
base:
base(this:10054048)
base:
base(this:10054044)
base:
base(this:10054040)
base:
base(this:10054036)
base:
base(this:10054032)
base:
base(this:10054028)
base:
base(this:10054024)
base:
base(this:10054020)
Bemærk at derived destructor ikke bliver kaldt selvom den er virtuel, og for
Borland C++Builder er pointerværdierne (forklarligt) helt hen i skoven
Min konklussion:
Brug std::vector i stedet for manuelt at allokere og frigive arrays af
objekter, hvis det overhovedet er muligt. Det er langt simplere, sikrere og
stadig meget effektivt.
Hvis det ikke er muligt så _kend_ reglerne og lad være med at basere sig på
at en eller anden "tilfældig" compiler måske gør hvad man ønskede - de kan
ændre det i næste version uden man er opmærksom på det.
Venlig hilsen
Mogens Hansen