What’s so bad about pointers in C++?

To continue the discussion in Why are pointers not recommended when coding with C++?

Suppose you have a class that encapsulates objects which need some initialisation to be valid – like a network socket.

// Blah manages some data and transmits it over a socket
class socket; // forward declaration, so nice weak linkage.      

class blah
{
  ... stuff 
  TcpSocket *socket;
}

~blah {
   // TcpSocket dtor handles disconnect
   delete socket; // or better, wrap it in a smart pointer
}

The ctor ensures that socket is marked NULL, then later in the code when I have the information to initialise the object.

// initialising blah
if ( !socket ) {
   // I know socket hasn't been created/connected
   // create it in a known initialised state and handle any errors 
   // RAII is a good thing ! 
   socket = new TcpSocket(ip,port);
}

// and when i actually need to use it
if (socket) {
   // if socket exists then it must be connected and valid 
}

This seems better than having the socket on the stack, having it created in some ‘pending’ state at program start and then having to continually check some isOK() or isConnected() function before every use.
Additionally if TcpSocket ctor throws an exception it’s a lot easier to handle at the point a Tcp connection is made rather than at program start.

Obviously the socket is just an example, but I’m having a hard time thinking of when an encapsulated object with any sort of internal state shouldn’t be created and initialised with new.

4

In general, programming constructs and techniques are commonly considered to be ‘bad’ when there are ‘better’ alternatives available for a particular task.
The use of a pointer may be technically correct in a lot of places, but it’s rare in C++ for a situation to arise where the use of a raw pointer doesn’t have a better alternative.

Most of the time, using references, smart pointers, iterators and standard library containers will result in safer/cleaner/more idiomatic code when compared to an equivalent solution using pointers; and usually at no extra cost to the programmer (quite frequently at a lower cost in fact).

There will always be occasions when a raw pointer is the most sensible option, and in those cases nobody gains by trying to find “clever” ways of avoiding pointers; particularly if avoiding a raw pointer means risking larger breaking changes to working legacy code which may otherwise have not needed to change; but for new code at least these situations are unusual for anybody using a modern C++11 implementation.

3

Pointers do have good reasons to be used too, as you argue. Though, in most cases you should get away with the standardized smart pointers introduced in C++11 to gain additional safety, while retaining the flexibility pointers give to you.

Though, it’s also true that they might seem confusing to people who aren’t so familiar with C++, so from maintenance perspective it’d be perhaps best to rely on the most simplest to understand techniques and methodologies to implement things.

2

In my opinion the pointers are described as difficult to handle or bad because they break 2 important aspects of any application design:

  • semantics
  • syntax

if you remember, a basic concept in the programming world is given by the fact that if I wrote 4 on a blackboard, this means nothing until i give a context and a semantic to what i have wrote on the blackboard, for example if after i have wrote 45 i say that what is on the blackboard it’s my age, you can get 45 as a real information, but without a context/semantics that 45 is useless and without a clear interpretation: the real information and its representation are different.

This is even clearer in technology like OpenGL, you can do almost nothing with your pointer if you don’t supply a context, the same thing happens in C++, if you don’t provide a context ( a target type ) for a pointer or a reference, the pointer alone means nothing and it’s useless.

The syntax is also important because it set boundaries about the business logic of your application and the lifetime of your components, pointers can potentially break all the boundaries and your business logic, never the less, pointers contains references so they do not even have a real state, they just point to something in memory that they can’t handle during the lifetime of your application, they are more like post-it with a memory address rather than objects with a well defined state and a well defined lifetime.

All the major difference between the old C++ and C++11 are differences about design, which means syntax and semantics that can drive the logic of your application; the smart pointers are nothing more than pointers but with a big plus related to a specific design that comes within the pointer itself, so you can have more control over it.

In the end the pointers can’t have a state and need a context to be handled, this is something that a safe and good application design can’t usually accept, the smart pointers are a step in the design oriented world which is basically the modern approach to the programming world.

4

The pointer is definitely not a bad thing, it gives you direct access to the memory, for the best performance.
Sometimes it is difficult to track the lifetime, when the pointer needs to be passed around classes, this is where the smart pointer can help. If you can sacrifice the little performance impact, then yes, use smart pointer if it is available.

The bad thing about using smart pointer is the dependency of the header file for the class. With raw pointer, you can just forward declare the class/struct, and have a cleaner dependency during compilation.
You must also ensure the smart pointer you use is thread-safe in case of multi-threading application.

If your class is simple enough, I would say stick with regular pointer than a smart one.

Pointers are bad for the following reasons:

  1. Information about memory areas disappears. It is no longer clear if your TcpSocket memory is inside the blah object or outside of it. References and composition can fix it. (reference=outside, composition=inside)
  2. Pointer can be NULL. How well you expect the program to work if the function call behaviour is not respected. If you call connect() function, it better do the connection, but failing simply because some ptr is NULL is not good behaviour — failures should have real reasons like network disconnected. Failing simply because some previous call failed is not good behaviour.
  3. Dynamic behaviour like the ptr==NULL should be done with booleans and not this kind of hidden behaviour where ptr==NULL. Then it would be easier to figure out the reason for the failure when booleans have proper names independent of the pointer.
  4. Best choice for failures is that they just never happen.
  5. 2nd best choice is that part of the application is disabled when network is not available – like no new information appears, and connection is restored as soon as possible.
  6. If your socket functions can fail, the function prototype better have that information. Your void connect() is not acceptable, int connect() with error code is better. Returning some object which contains fail bit is also ok.

Example of what kind of alternatives are available: (the composition one)

class Blah {
public:
  Blah(ip,port) : s(ip,port) { }
private:
  TcpSocket s;
  bool failbit;
};

Or with references:

class Blah {
public:
  Blah(TcpSocket &s) : s(s) { }
private:
  TcpSocket &s;
};

If the connection has to be created afterwards, like address not known early enough in constructor, then use this:

class Blah {
public:
   Blah() : sock(NULL) { }
   TcpSocket &connect(ip, port) {
     delete sock;
     sock = new TcpSocket(ip,port);
     return *sock;
    }
  ~Blah() { delete sock; }
private:
  TcpSocket *sock;
};

But this is usually not the best alternative… (call connect twice and previous one loses connection — the returned TcpSocket must not be stored anywhere) The next alternative will need std::vector < TcpSocket*>…

class Blah {
public:
   Blah() : vec(), error("logfile.txt") { }
   int connect(ip,port) {
      vec.push_back(new TcpSocket(ip,port));
      return vec.size()-1;
   }
   int write(int conn, char *data) {
      if (vec[conn])
         { vec[conn]->write(data); return OK; }
      else return ERR;
   }
  TcpSocket &connection(int conn) const 
      { if (vec[conn]) return *vec[conn]; else return error; }
  void disconnect(int conn) { delete vec[conn]; vec[conn]=NULL; }
   ~Blah() { for(int i=0;i<vec.size();i++) delete vec[i]; }
private:
   std::vector<TcpSocket*> vec;
   TcpSocket error;
};

Note that returning index to the connection std::vector prevents removing connections (indexes will get broken/have to make them NULL). The last one just have a problem that connect() return value and write() return value is different. Should use some kind of type checking trick to make them different ints:

struct Err { int error; };
Err write(int conn, char *data);

5

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật