@zStupan,
I have, still, an unanswered question. You present the appearance of either a high end student, or a professional in need of expressing in code some ideas for a professional (or study) purpose. I’ve all but excluded the notion that you’re making a product.
Many engineers, scientists, researchers, and even graduate or PhD students in such situations choose Python. I personally loathe Python, but that’s a prejudice born from the fact I’ve been a C++/C developer for a long time. I have similar reactions to other languages.
The choice of C++ shouldn’t be taken lightly. If you’re studying C++, and that’s the underlying purpose, I have one avenue of response. If you’re a researcher (student or professional), I have another.
Bluntly, C++ is nasty. There are many ways of doing the same thing, and many should be avoided. There’s more to learn in order to use the language effectively, reliably and efficiently (both from the perspective of execution and development) when compared with other languages. I say this despite that I far prefer C++ to most any modern language, but then I've known it for decades.
I need to better understand why you intend write in C++. I can see, based on experience and the writings of many observing the same history, you are likely to end up chasing down bugs to a depressing end. That’s not to say you won’t succeed, but how I should advise you depends greatly on why you’ve chosen C++, and what you’re really doing in the larger context. I’ve asked earlier, but I still don’t understand that part sufficiently to be of REAL help here. It may be that my best advice is to suggest you switch to C# or Java if you’re not going to study smart pointers.
To that end, I cite this line from you:
"I don't really get smart pointers, so I'll just make sure to delete them properly."
This is, in part, what tells me to pause and ensure I know the environment in which you’re operating, and why you’ve chosen C++.
We know from research that pointers and allocation (they go together) is historically known to represent about 30% of all bugs in C (and C++ when used exclusively). One of the worst types of bugs related to issues with pointers is that the problem (or crash) happens well removed from the real source of the bug itself. It creates quite a debugging mystery. It has been known to soak up weeks and months. These kinds bugs have persisted in professional products for as long as years before they were found.
One of the single most important developments in C++ was the smart pointer. At first it wasn't even part of the language. I remember when it happened. I was a late 20's (almost 30) something engineer at the time. C++ was not yet in full vogue, but convincing. C was still more in use. C++ templates didn't exist, and so smart pointers in C++ didn't either. There were intrusive reference counted pointers, but those aren't what we now call smart pointers - one had to derive from a common base representing the reference count.
When templates were released (around 1990), one of the first things every interested programmer did with them was to fashion their own smart pointers (usually reference counted). The second was usually to fashion some containers (from lists to trees of some kind). It was after that when the STL was released, and shared_ptr was not in it. The shared_ptr came from Boost, then added to C++ much later.
An oversimplified but illustrative example of the smart pointer is this, which clarifies “what to get about it”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
using namespace std;
template< typename T> class SPtr
{
private:
SPtr * thePointer;
public:
SPtr( Sptr * s ) : thePointer( s ) {}
~ SPtr() { if ( thePointer ) delete thePointer; }
SPtr * operator ->() { return thePointer; }
};
void SomeFunc()
{
SPtr< AType > p( new AType() );
p->x = 1; // assuming AType has an integer x member
}
| |
This naive version demonstrates the single most important aspect of them. They delete what they own in the destructor.
User code allocation with 'new' may take different forms (make_unique, make_shared), but no explicit delete is performed. Although SomeFunc includes the allocation of AType with 'new', it is deleted by the smart pointer when SomeFunc returns, even if an exception occurs (and that's key to their importance).
Using the pointer with the ‘->’ operator is the same as with raw pointers.
This naive example resembles (very loosely) std::scoped_ptr. You expect there’s no support for copying the pointer (which std::scoped_ptr will deny). Factually, this naive code would allow copies, but with disastrous implications (the memory pointed to would be deleted twice). The std::scoped_ptr denies copies (or moves), while the std::unique_ptr enforces moves (but prevents copies). The std:shared_ptr implements copies with reference counting, and thus eliminates all manual burden of defining ownership, or of deleting the allocated memory.
That’s a considerable benefit in the long run, because copying pointers around is one source of bugs even though that’s one of the reasons one likes and uses pointers. The contradictory nature of those two ideas is one of the many reasons smart pointers were created for C++, and why many advise the use of C#, Java or other languages (because they don’t have raw pointers - or at least they're behind a barrier - implementing a scheme closely resembling the behavior of std::shared_ptr, which C# calls references). Experienced C# programmers may object that C# CAN use pointers, but that is only in code declared by the 'unsafe' keyword, which I consider a derogatory judgment that happens to be true relative to C# code outside the 'unsafe' context.
The quote I show from you above hints you’re not familiar with RAII. The acronym is described by it’s author is poor (not a good marketing term). The naive smartpointer code I post shows what it is. Initialization (one of the I’s in the acronym) acquires (the A in the acronym) a resource, in this case allocated memory. Such resources could be anything that is opened which must subsequently be closed, or allocated and subsequently freed. The strong association between constructors and destructors is how C++ implements RAII. The destructor deals with closing or freeing the resource. This paradigm is key in C++. It isn’t in Java or C#, except in the hidden implementation of what they call references (the behavior I claim resembles std::shared_ptr).
This, in turn, suggests that C++ is very new to you. Implementing a target of such ambition as computational geometry may be ill advised, because you are (likely) diving too deep into the woods, and will end up spending considerable time with details you’ll find bothersome and delaying. Unless your purpose is to study C++, or for other reasons you require it, you may be better to switch to C# or Java. If not, you should consider a pause to study smart pointers before you continue.
I’m still not sure which. However, merely choosing raw pointers is not wise, and I have historical and empirical reasons for insisting on clarifying the issue. A modern C++ programmer without smart pointers is a fundamental contradiction unless there’s seriously well considered reasoning behind the choice.