53

I read from somewhere that when using C++ it is recommended not to use pointers. Why is pointers such a bad idea when you are using C++. For C programmers that are used to using pointers, what is the better alternative and approach in C++?

Destructor
  • 174
  • 1
  • 10
Joshua Partogi
  • 3,845
  • 11
  • 34
  • 43
  • 44
    please link to "somewhere". The context might be very relevant. –  Mar 11 '11 at 06:53
  • 1
    [This question](http://stackoverflow.com/questions/57483/difference-between-pointer-variable-and-reference-variable-in-c/57492#57492) is hopefully useful for you. – That Realtor Programmer Guy Mar 18 '11 at 08:00
  • Most of these answers refer to avoiding memory leaks as the primary reason. I can't remember the last time one of our apps had a memory leak issue despite using pointers. If you have memory leak issues then you aren't using the right tools or you don't know what you are doing. Most development environments have a way to automatically check for leaks built in. I think memory leak issues are far more difficult to track down in garbage collected languages because their occurrence is far more subtle and you frequently need a 3rd party tool to track down the culprit. – Dunk Nov 13 '14 at 22:12
  • 1
    Adding to @Dunk 's comment, sometimes built-in garbage collectors in higher-level languages simply do not work right. ActionScript 3's garbage collector doesn't, for instance. There's a bug in it right now that has to do with `NetConnection` instances disconnecting from the server (http://stackoverflow.com/questions/14780456/why-does-a-closed-netconnection-that-has-no-event-listeners-or-references-stick), as well as an issue with there being multiple objects in a program that it will specifically refuse to ever collect ... – Panzercrisis Jan 07 '15 at 13:54
  • ... (http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/garbage-collection.html - search for `GCRoots are never garbage collected.` and the paragraph started by `The MMgc is considered a conservative collector for mark/sweep.`). Technically this is a problem in Adobe Virtual Machine 2, not AS3 itself, but when you have problems like this in higher-level languages, which have garbage collection essentially built in, you often don't have any true way within the language to debug these issues completely out of the program. ... – Panzercrisis Jan 07 '15 at 13:59
  • ... It is known to occur, at least in the case of Flash, but possibly on some other platforms as well, for developers to occasionally have to mimic C++-style destructors that get called explicitly and set all accessible member references to `null`; this way, even if the garbage collector refuses to collect something like a `GCRoot`, other stuff that's contained directly or indirectly by the `GCRoot` will still get collected on its own. ...And I really didn't mean to digress like that, but I agree with what @Dunk was saying; people get this idea that pointers in C++ automatically imply ... – Panzercrisis Jan 07 '15 at 14:01
  • ... horrible memory leaks, and that garbage-collected languages such as VB.NET, Java, and AS3 are essentially an infallible tool that lead to absolute perfection, but this is incorrect. You are still capable of coding serious memory leaks in these languages, in addition to any that intrinsically exist. At least when using pointers in C++, you are in a position to be able to actually fix any memory leaks that are known to exist, instead of only certain ones that the language "permits" you to fix. – Panzercrisis Jan 07 '15 at 14:11

9 Answers9

116

Since I’m the one who published the polemic “don’t use f*cking pointers” I feel that I should comment here.

First of all, as a polemic it obviously represents an extreme viewpoint. There are definitely legitimate uses of (raw, and other) pointers. But I (and many professional C++ programmers) maintain that pointers in C++ are vastly overused. But what we really mean is the following:

First:

Raw pointers must under no circumstances own memory.

Here, “own memory” essentially means that at some point delete is called on that pointer (but it’s more general than that). This statement can safely be taken as an absolute. The only exception is when implementing your own smart pointer (or other memory management strategy). And even there you should normally still use a smart pointer at low level.

The rationale for this is quite simple: raw pointers which own memory introduce a source of error. And these errors are prolific in existing software: memory leaks and double deletion – both a direct consequence of unclear resource ownership (but going in opposite direction).

This problem can be entirely eliminated, at virtually no cost, by simply using smart pointers instead of raw pointers (caveat: this still requires thinking, of course; shared pointers can lead to cycles and thus once again to memory leaks – but this is easily avoidable).

Second:

Most uses of pointers in C++ are unnecessary.

Unlike other languages, C++ has very strong support for value semantics and simply doesn’t need the indirection of pointers. This wasn’t immediately realised – historically, C++ was invented to facilitate easy object orientation in C, and relied heavily on constructing object graphs which were connected by pointers. But in modern C++, this paradigm is rarely the best choice, and modern C++ idioms often don’t need pointers at all. They operate on values rather than pointers.

Unfortunately, this message has still not caught on in large parts of the C++ user community. As a result, most of the C++ code that is written is still littered with superfluous pointers which make the code complex, slow and faulty / unreliable.

For somebody who knows modern C++, it’s clear that you very rarely need any pointers (either smart or raw; except when using them as iterators). The resulting code is shorter, less complex, more readable, often more efficient and more reliable.

Konrad Rudolph
  • 13,059
  • 4
  • 55
  • 75
  • 6
    Sigh... this should really be the answer with 30+ upvotes... especially for the second point. Pointers are just rarely even *necessary* in modern C++. – Charles Salvia Sep 01 '12 at 14:21
  • 2
    what about eg. Gui object owns a bunch of doc objects. It has these as pointers both so the class can be forward declared (avoids recompiles) and so that the object can be initialised when created (with new) rather than being created on the stack in some empty state and then filed-in later? This seems a perfectly valid use of pointers - shouldn't all encapsulated objects be on the heap? – Martin Beckett Sep 01 '12 at 16:42
  • 4
    @Martin GUI objects are one case where pointer object graphs are indeed the best solution. But the edict against memory-owning raw pointers still stands. Either use shared pointers throughout or develop a proper ownership model and have only weak (= non-owning) relations between the controls via raw pointers. – Konrad Rudolph Sep 01 '12 at 17:11
  • 1
    What about PODs of moderate size which need to be stored in a std container, without ptr_vec? I've been in a situation where the container (vector for a heap) needed fast inter-element swaps. This was also in a hot section, so shared ptrs wouldn't do. – VF1 Nov 13 '14 at 20:58
  • 1
    @VF1 `std::unique_ptr`. Also, why not `ptr_vec`? But usually a value vector with will still swap faster (especially with move semantics). – Konrad Rudolph Nov 13 '14 at 21:04
  • Ah - I recall why both of those didn't work - the data was stored in another structure, so they weren't owning pointers in the first place. – VF1 Nov 15 '14 at 05:33
  • 1
    What, in that case, is the "correct" approach to building a graph in C++? Or any data structure that recursively references its elements? The problem is that it is (still?) UB to use most containers specialized with incomplete types. You cannot, for example, have a `node` that contains `std::deque`, or `std::deque>`, or `std::deque::iterator`!! All you're stuck with is a `std::deque`. – gaazkam Jun 11 '17 at 07:45
  • 1
    PS. Yes I know you can use `std::vector`, `std::list` and `std::forward_list` that way, http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4510.html , but this is not always enough. Sometimes you need `std::map` for example. Bottom line: The prohibition to specialize many containers and other facilities from standard library like `reference_wrapper` seems to me as a use case of pointers to which there is no alternative. – gaazkam Jun 11 '17 at 07:48
  • 1
    @gaazkam Nobody forced you to use only standard containers. Boost for instance has a map implementation with support for incomplete types. Another solution is to use type erasure; `boost::variant` with a `recursive_wrapper` is probably my favourite solution to represent a DAG. – Konrad Rudolph Jun 11 '17 at 08:17
64

I think they mean you should use smart pointers instead of regular pointers.

In computer science, a smart pointer is an abstract data type that simulates a pointer while providing additional features, such as automatic garbage collection or bounds checking. These additional features are intended to reduce bugs caused by the misuse of pointers while retaining efficiency. Smart pointers typically keep track of the objects they point to for the purpose of memory management.

The misuse of pointers is a major source of bugs: the constant allocation, deallocation and referencing that must be performed by a program written using pointers introduces the risk that memory leaks will occur. Smart pointers try to prevent memory leaks by making the resource deallocation automatic: when the pointer (or the last in a series of pointers) to an object is destroyed, for example because it goes out of scope, the pointed object is destroyed too.

In C++ the emphasis would be on garbage collection and preventing memory leaks (just to name two). Pointers are a fundamental part of the language, so not using them is pretty much impossible except in the most trival of programs.

jmq
  • 6,048
  • 5
  • 28
  • 39
  • 22
    typically its not strictly garbage collection in the classical sense, more reference counting. At least in the smart ptr I'm used to ([boost|std]::shared_ptr) – Doug T. Mar 11 '11 at 14:37
  • 4
    This answer is very limited to smart pointer, which is only a small aspect of the problem. Additionally, smart pointer are not garbage collection. – deadalnix Jun 07 '12 at 12:37
  • 3
    Also RAII in general. – Klaim Jun 07 '12 at 13:49
  • 3
    No, this is not what’s meant. It is only *one* aspect, and not the most important one. – Konrad Rudolph Sep 01 '12 at 13:20
  • I think smart pointers are the most important aspect, but I agree there are many others. – DeadMG Sep 01 '12 at 13:36
  • No, that's not what they mean, or not what they should mean. It's a solid recommendation to just avoid pointers unless you actually need them; and if you do need them - don't use raw new and delete, but rather smart pointers. – einpoklum Aug 21 '23 at 22:06
15

Simply because there are abstractions available to your which hide the more temperamental aspects of using pointers, such as access to raw memory and cleaning up after your allocations. With smart pointers, container classes, and design patterns like RAII, the need for using raw pointers is diminished. That said, like any abstraction, you should understand how they actually work before moving beyond them.

Ed S.
  • 2,758
  • 2
  • 21
  • 24
12

Relatively simply, the C mentality is "Got a problem? Use a pointer". You can see this in C strings, function pointers, pointers-as-iterators, pointer-to-pointer, void pointer- even in the early days of C++ with member pointers.

But in C++ you can use values for many or all of these tasks. Need a function abstraction? std::function. It's a value that's a function. std::string? It's a value, that's a string. You can see similar approaches all over C++. This makes analyzing the code vastly easier for both humans and compilers.

DeadMG
  • 36,794
  • 8
  • 70
  • 139
  • 1
    In C++: Got a problem? Use a pointer. Now you have 2 problems... – Daniel Santos Dec 15 '15 at 10:50
  • 1
    I think this answer can be further expanded now. You think `std::string` and other stl containers are too heavy? Now you got `string_view`, `span`, and `ranges::views`. Literally just a pointer and a size, or two pointers, and you never need to worry about all the pointer related gotchas. – Ranoiaetep Nov 21 '21 at 04:44
10

One of reasons is too wide application of pointers. They can be used for iteration over containers, for avoiding copying large objects when passing to function, non-trivial life-time management, accessing to random places in memory, etc. And once you used them for one purpose, other their features become available immediately independently on intent.

Selection of a tool for exact purpose makes code simpler and intent more visible - iterators for iterations, smart pointers for life-time management, etc.

maxim1000
  • 745
  • 4
  • 8
3

Besides the reasons already listed, there is an obvious one: better optimisations. Aliasing analysis is far too complicated in presense of a pointer arithmetics, whereas references hints an optimiser, so a much deeper aliasing analysis is possible if only references are used.

SK-logic
  • 8,497
  • 4
  • 25
  • 37
2

Beside the risk of memory leaks stated by @jmquigley pointer and pointer arithmetic can be considered problematic because pointers can point everywhere in memory causing "hard to find bugs" and "security vulnerableties".

That is why they were nearly abandoned in C# and Java.

DeveloperDon
  • 4,958
  • 1
  • 26
  • 53
k3b
  • 7,488
  • 1
  • 18
  • 31
-1

C++ supports most of C, features, plus Objects and Classes. C already had pointers and other stuff.

Pointers are a very useful technique, that can be combined with Object Orientation, and C++ supports them. But, this technique, is difficult to teach and difficult to understand, and, its very easy to cause unwanted errors.

Many new programming languages pretend not to use pointers with objects, like Java, .NET, Delphi, Vala, PHP, Scala. But, pointers are still used, "behind the scenes". These "hidden pointer" techniques are called "references".

Anyway, I consider pointer (s) as a Programming Pattern, as a valid way to solve certain problems, as well as Object Oriented Programming does.

Other developers may have a different opinion. But, I suggest students and programmers learn how to:

(1) Use pointers without objects

(2) objects without pointers

(3) explicit pointers to objects

(4) "hidden" pointers to objects ( A.K.A. reference) ;-)

In that order.

Even if is difficult to teach, and difficult to learn. Object Pascal (Delphi, FreePascal, others) and C++ (not Java or C#) can be used for those goals.

And, later, novice programmers, can move to "hidden pointers to objects" programming languages like: Java, C#, Object Oriented PHP, and others.

umlcat
  • 2,146
  • 11
  • 16
-6

Talking about VC6, when you cast a pointer of a class (that you instantiate) into a variable (e.g. DWORD), even if this pointer is local you can access the class over all the functions that use the same heap. The instantiated class is defined as local but in fact it is not. As far as I know, any address of a heap variable, structure or class is unique along all the life of the hosting class.

Example:

class MyClass1 {
    public:
        void A (void);
        void B (void);
        void C (void);
    private:
        DWORD dwclass;
};

class MyClass2 {
    public:
        int C (int i);
};

void MyClass1::A (void) {
    MyClass2 *myclass= new MyClass2;
    dwclass=(DWORD)myclass;
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    int i = myclass->C(0); // or int i=((MyClass2 *)dwclass)->C(0);
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    delete myclass;
}

EDIT Thats a very little part of the original code. The CSRecodset class is only a casting class of CXdbRecordset, where all the real code is. Doing so I can let the user take benefit of what I wrote without loosing my rights. I do not pretend to demonstrate that my database engine is professional but it really works.

//-------------------------------------
class CSRecordSet : public CSObject
//-------------------------------------
{
public:
    CSRecordSet();
    virtual ~CSRecordSet();
    // Constructor
    bool Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef);
    //Open, find, close
    int OpenRst(bool bReadBlanks=0,bool bCheckLastSql=0,bool bForceLoad=0,bool bMessage=1);     // for a given SQL
    int FindRecord(bool bNext);         // for a given SQL
    // TABLE must be ordered by the same fields that will be seek
    bool SeekRecord(int nFieldIndex, char *key, int length=0);  // CRT bsearch
    bool SeekRecord(int nFieldIndex, long key);     
    bool SeekRecord(int nFieldIndex, double key, int decimals);     
    bool SeekRecord(XSEK *SEK);     
    bool DeleteRecord(void);
    bool Close(void);
    // Record Position:
    bool IsEOF(void);           // pointer out of bound
    bool IsLAST(void);          // TRUE if last record
    bool IsBOF(void);           // pointer out of bound
    bool IsOpen(void);
    bool Move(long lRows);      // returns FALSE if out of bound
    void MoveNextNotEof(void);  // eof is tested
    void MoveNext(void);        // eof is not tested
    void MovePrev(void);        // bof is tested
    void MoveLast(void);
    void MoveFirst(void);
    void SetAbsolutePosition(long lRows);
    long GetAbsolutePosition(void);
    void GoToLast(void); // Restore position after a Filter
    // Table info
    long GetRecordCount(void);
    int GetRstTableNumber(void);
    int GetRecordLength(void); //includes stamp (sizeof char)
    int GetTableType(void);
    // Field info
    int GetFieldCount(void);
    void GetFieldName(int nFieldIndex, char *pbuffer);
    int GetFieldIndex(const char *sFieldName);
    int GetFieldSize(int nFieldIndex);
    int GetFieldDGSize(int nFieldIndex); // String size (i.e. dg_Boolean)
    long GetRecordID(void);
    int GetStandardFieldCount(void);
    bool IsMemoFileTable(void);
    bool IsNumberField(int nFieldIndex);
    int GetFieldType(int nFieldIndex);
    // Read Field value
    bool GetFieldValue(int nFieldIndex, XdbVar& var);
    bool GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer);
    char *GetMemoField(int nMemoFieldIndex, char *pbuffer, int buf_size);
    bool GetBinaryField(unsigned char *buffer,long *buf_size);
    // Write Field value
    void Edit(void); // required
    bool SetFieldValue(int nFieldIndex, XdbVar& var);
    bool SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer);
    bool Update(void); // required
    // pointer to the same lpSql
    LPXSQL GetSQL(void);
};

//---------------------------------------------------
CSRecordSet::CSRecordSet(){
//---------------------------------------------------
    pClass |= (CS_bAttach);
}
CSRecordSet::~CSRecordSet(){
    if(pObject) delete (CXdbRecordset*)pObject;
}
bool CSRecordSet::Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef){
    CXdbQueryDef *qr=(CXdbQueryDef*)pQueryDef->GetObject();
    CXdbTables *db=(CXdbTables*)pDataBase->GetObject();
    CXdbRecordset *rst = new CXdbRecordset(db,qr);
    if(rst==NULL) return 0;
    pObject = (unsigned long) rst;
    return 1;
}
bool CSRecordSet::Close(void){
    return ((CXdbRecordset*)pObject)->Close();
}
int CSRecordSet::OpenRst(bool bReadBlanks,bool bCheckLastSql,bool bForceLoad, bool bMessage){
    unsigned long dw=0L;
    if(bReadBlanks) dw|=SQL_bReadBlanks;
    if(bCheckLastSql) dw|=SQL_bCheckLastSql;
    if(bMessage) dw|=SQL_bRstMessage;
    if(bForceLoad) dw|=SQL_bForceLoad;

    return ((CXdbRecordset*)pObject)->OpenEx(dw);
}
int CSRecordSet::FindRecord(bool bNext){
    return ((CXdbRecordset*)pObject)->FindRecordEx(bNext);
}
bool CSRecordSet::DeleteRecord(void){
    return ((CXdbRecordset*)pObject)->DeleteEx();
}
bool CSRecordSet::IsEOF(void){
    return ((CXdbRecordset*)pObject)->IsEOF();
}
bool CSRecordSet::IsLAST(void){
    return ((CXdbRecordset*)pObject)->IsLAST();
}
bool CSRecordSet::IsBOF(void){
    return ((CXdbRecordset*)pObject)->IsBOF();
}
bool CSRecordSet::IsOpen(void){
    return ((CXdbRecordset*)pObject)->IsOpen();
}
bool CSRecordSet::Move(long lRows){
    return ((CXdbRecordset*)pObject)->MoveEx(lRows);
}
void CSRecordSet::MoveNextNotEof(void){
    ((CXdbRecordset*)pObject)->MoveNextNotEof();
}
void CSRecordSet::MoveNext(void){
    ((CXdbRecordset*)pObject)->MoveNext();
}
void CSRecordSet::MovePrev(void){
    ((CXdbRecordset*)pObject)->MovePrev();
}
void CSRecordSet::MoveLast(void){
    ((CXdbRecordset*)pObject)->MoveLast();
}
void CSRecordSet::MoveFirst(void){
    ((CXdbRecordset*)pObject)->MoveFirst();
}
void CSRecordSet::SetAbsolutePosition(long lRows){
    ((CXdbRecordset*)pObject)->SetAbsolutePosition(lRows);
}
long CSRecordSet::GetAbsolutePosition(void){
    return ((CXdbRecordset*)pObject)->m_AbsolutePosition;
}
long CSRecordSet::GetRecordCount(void){
    return ((CXdbRecordset*)pObject)->GetRecordCount();
}
int CSRecordSet::GetFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetFieldCount();
}
int CSRecordSet::GetRstTableNumber(void){
    return ((CXdbRecordset*)pObject)->GetRstTableNumber();
}
void CSRecordSet::GetFieldName(int nFieldIndex, char *pbuffer){
    ((CXdbRecordset*)pObject)->GetFieldName(nFieldIndex,pbuffer);
}
int CSRecordSet::GetFieldIndex(const char *sFieldName){
    return ((CXdbRecordset*)pObject)->GetFieldIndex(sFieldName);
}
bool CSRecordSet::IsMemoFileTable(void){
    return ((CXdbRecordset*)pObject)->IsMemoFileTable();
}
bool CSRecordSet::IsNumberField(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->IsNumberField(nFieldIndex);
}
bool CSRecordSet::GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer){
    return ((CXdbRecordset*)pObject)->GetFieldValueIntoBuffer(nFieldIndex,pbuffer);
}
void CSRecordSet::Edit(void){
    ((CXdbRecordset*)pObject)->Edit();
}
bool CSRecordSet::Update(void){
    return ((CXdbRecordset*)pObject)->Update();
}
bool CSRecordSet::SetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->SetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer){
    return ((CXdbRecordset*)pObject)->SetFieldValueFromBuffer(nFieldIndex,pbuffer);
}
bool CSRecordSet::GetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->GetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SeekRecord(XSEK *SEK){
    return ((CXdbRecordset*)pObject)->TableSeek(SEK);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,char *key, int length){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,key,length);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,long i){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,i);
}
bool CSRecordSet::SeekRecord(int nFieldIndex, double d, int decimals)
{
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,d,decimals);
}
int CSRecordSet::GetRecordLength(void){
    return ((CXdbRecordset*)pObject)->GetRecordLength();
}
char *CSRecordSet::GetMemoField(int nMemoFieldIndex,char *pbuffer, int BUFFER_SIZE){
    return ((CXdbRecordset*)pObject)->GetMemoField(nMemoFieldIndex,pbuffer,BUFFER_SIZE);
}
bool CSRecordSet::GetBinaryField(unsigned char *buffer,long *buf_size){
    return ((CXdbRecordset*)pObject)->GetBinaryField(buffer,buf_size);
}
LPXSQL CSRecordSet::GetSQL(void){
    return ((CXdbRecordset*)pObject)->GetSQL();
}
void CSRecordSet::GoToLast(void){
    ((CXdbRecordset*)pObject)->GoToLast();
}
long CSRecordSet::GetRecordID(void){
    return ((CXdbRecordset*)pObject)->GetRecordID();
}
int CSRecordSet::GetStandardFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetStandardFieldCount();
}
int CSRecordSet::GetTableType(void){
    return ((CXdbRecordset*)pObject)->GetTableType();
}
int CSRecordSet::GetFieldType(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldType(nFieldIndex);
}
int CSRecordSet::GetFieldDGSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldDGSize(nFieldIndex);
}
int CSRecordSet::GetFieldSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldSize(nFieldIndex);
}

EDIT: requested by DeadMG:

void nimportequoidumomentquecaroule(void) {

    short i = -4;
    unsigned short j=(unsigned short)i;

}
Salvador
  • 101
  • 1
  • 1
    This description could be enhanced significantly by some code to illustrate what you are describing. I have a sense that it related to the original question, but if you warned us of a danger in this scenario, it would help elaborate the questioner's topic. – DeveloperDon Aug 20 '12 at 17:59
  • 1
    That cast to `DWORD` is abusive and possibly incorrect (DWORD isn't necessarily wide enough to hold a pointer). If you need an untyped pointer, use `void*` - but when you find yourself needing that in C++, you've often got a design problem in your code you should fix. – Mat Aug 21 '12 at 03:41
  • Salvador, I think you are trying to say something about VC6 and how it has unusual and unexpected pointer handling. The example could benefit by comments, and if you are seeing warnings from the compiler, they might be informative with regard to relating your answer to the question. – DeveloperDon Aug 25 '12 at 05:38
  • @Mat That example is for a 32 bit OS and the VC6++ compiler. – Salvador Sep 01 '12 at 10:45
  • @DeveloperDon This is a very temporary code that I wrote for you, I did not compiled it. The original code is similar (but much bigger, indeed it was published in 2006) and has not even one warning. What I tried to notice is that MyClass2 *myclass is a local variable instantiated at MyClass1, which dies with MyClass1. Casted to a heap variable as dwclass it may be reused and deleted in other functions. I should perhaps comment that I could execute this kind of code a **billion times** (really much more) without any error, even inside very deep loops. – Salvador Sep 01 '12 at 10:57
  • 6
    Talking about bad code in an absolutely ancient compiler? No thanks. – DeadMG Sep 01 '12 at 13:40