I'm learning C++ and kind of confused why the instructor keeps initializing a pointer to nullptr instead of just directly allocate memory on the heap
int *new_storage {nullptr};
new_storage = new int[size];
why cant he just do:
int *new_storage = new int[size];
is there any advantage of initializing a pointer to nullptr prior to memory allocation?
Instructors are people and they have their own habits. Doing it the second way is considered better by just about everyone, and if you asked him or her about it, you'd probably get agreement.
Of course, get this use of raw pointers out of your system. You need to know how it works, but modern C++ uses smart pointers. You'll want to transition to them as soon as you can do everything using raw pointers.
While you are learning any skill, it can be useful to take small steps. The challenge for every instructor is to figure out how small these steps should be.
In this case, I would agree with you: this is overdoing "small steps". But the bigger critique is that the instructor is teaching new[] to beginners. For the last 25 years or so, the recommended simple approach is std::vector<int>.
In a follow-up course, an instructor could teach how to use new[] to implement your own Vector class, but that should be for students who can already use std::vector<int>.
Related
I was looking at this tutorial about the stack and heap:
When to use new operator in C++ and when it should not be used?
And in the heap example, it uses the new keyword, but he began by initializing int* ptr1 to NULL. Is that important, and if so why? Or, is it just wasting space?
I looked at the code and tried thinking why use NULL first when you could just use int* ptr1 = new int(28);?
Side note:
If someone could also explain the stack and heap in laymans terms, it would be appreciated.
Initializing a pointer to nullptr on declaration is an excellent practice to adhere to.
But, what they did in the tutorial could be done better. I think it is more of an example of syntax than anything else.
If you can initialize when declaring, that is better and faster. Use nullptr instead of NULL, which is just a macro for 0 and that can be problematic.
If you want to learn more about pointers, learning smart pointers is recommended. They can be a really powerful way to avoid bugs and memory leaks.
What are the internal differences of choosing to use an std::vector vs a dynamically allocated array? I mean, not only performance differences like in this matching title question.
I mean, I try to design a library. So I want to offer a wrapper over an StackArray, that is just a C-Style array with some member methods that contains as a member T array[N]. No indirections and the new operator removed to force the implementor to have a array type always stored in the stack.
Now, I want to offer the dynamic variant. So, with a little effort, I just can declare something like:
template <typename T>
class DynArray
{
T* array,
size_t size,
size_t capacity
};
But... this seems pretty similar to a base approach to a C++ vector.
Also, an array stored in the heap can be resized by copying the elements to a new mem location (is this true?). That's pretty much the same that makes a vector when a push_back() operation exceeds its allocated capacity, for example, right?
Should I offer both API's if exists some notable differences? Or I am overcomplicated the design of the library and may I just have my StackArray and the Vector should be just the safe abstraction over a dynamically allocated array?
First there is a mindset (usually controversial) between the usage of the modern tools that the standard provides and the legacy ones.
You usually must be studing and asking things about C++ modern features, not comparing them with the old ones. But, for learning purposes, I have to admit that it's quite interesting dive deep somethimes in this topics.
With that in mind, std::vector is a collection that makes much more that just care about the bytes stored in it. There is a constraint really important, that the data must lie in contiguous memory, and std::vector ensures this in its internal implementation. Also, has an already well known, well tested implementation of the RAII pattern, with the correct usage of new[] and delete[] operators. You can reserve storage and emplace_abck() elements in a convenient and performant way which makes this collection really unique... there are really a lot of reasons that shows why std::vector is really different from a dynamically allocated array.
Not only is to worry about manual memory management, which almost an undesirable thing to do in modern C++ (embedded systems, or operating system themselves are a good point to discuse this last sentence). It's about to have a tool, std::vector<T> that makes your life as developer easier, specially in a prone-error language like C++.
Note: I say error-prone because it's a really hard to master language, which needs a lot of study and training. You can make almost everything in the world, and has an incredible amount of features that aren't begginer friendly. Also, the retrocompatibility constraint makes it really bigger, with literally thousand of things that you must care about. So, with a great power, always comes a great responsability.
Short Version:
Is there any acceptable reason for using non-smart pointers in modern C++?
Long Version:
we have a huge product that contains lot's of old C++ code and now we are trying to refactor it to the modern C++ era. Along with all the old fashioned code, there is huge amount of pointers passing around (mostly with SAL annotations to provide some sense of security) and I was wondering if we should change all of them to smart pointers or maybe leave some of them as is?
Trying to convert some of these codes, I ended up with a code that is simply arguable for over using smart pointers.
So the question is: is there such a thing as over using smart pointers?
Or in other words: is there any acceptable scenario for non-smart pointers these days?
Smart pointers (unique_ptr and shared_ptr) should be OWNING pointers (i.e., responsible for destruction of the object). The bottom line of using them is that any object created by new should be shoved into a unique_ptr ASAP, to prevent memory leaks. After that, the unique_ptr should end up being moved:
either into a shared_ptr if ownership should be shared,
or into a unique_ptr if ownership is determined by a scope (of a block, or the lifetime of an object).
releases should be rare. If your code passes non-owning pointers around, these should be:
raw pointers if they may be null, (obtained by get)
references if they may not be null, (obtained by get)
unique_ptrs by value if the aim of the call is transferring ownership. (in which case you'll need to move them)
Factory methods should return unique_ptrs by value. (because then, if you don't assign the return value of the factory method, the object is immediately de-allocated)
And check out Ali's answer regarding links to some philosophical points of handling legacy code. (Which I totally agree on)
Short Version:
Is there any acceptable reason for using non-smart
pointers in modern C++?
Short answer:
Definitely, if they only serve for observation, that is, they don't own the pointee. However, try to use references instead of pointers even in this case; use pointers only if you really need to make them optional (initialize with null_ptr then reassign later, for example).
Long Version:
we have a huge product that contains lot's of old C++ code and now we are trying to refactor it to the modern C++ era. [...]
Long answer:
As I am reading these lines this answer comes to mind:
Advice on working with legacy code
I wish I could upvote this answer more than once. I would quote: "[...] for each re-factor we have made we can justify 'this specific change will make the actual task we are doing now easier'. Rather than 'this is now cleaner for future work'."
Long story short, don't do big refactoring unless you really need to.
So the question is: is there such a thing as over using smart pointers?
In my opinion, std::shared_ptr is overused. It is very comfortable to use, and it gives you the illusion that you don't have to think about ownership issues. But that is not the whole picture. I fully agree with Sean Parent: "a shared pointer is as good as a global variable." Shared pointers can also introduce very difficult ownership issues, etc.
On the other hand, if you need to allocate something on the heap, use a unique_ptr. You can't overuse it, if you really need heap allocation. In my experience, using unique_ptr also leads to cleaner and easier to understand code, as the ownership issues become self-explanatory.
Interesting talks from Sean Parent on how to avoid / reduce the usage of pointers are:
Inheritance Is The Base Class of Evil
Value Semantics and Concepts-based Polymorphism
Hope this helps.
Yes, raw pointers still have a uses as an "optional reference". I.e. a T* is similar to a T&. Neither implies ownership, but a T* can be a nullptr.
Check out the talks here: http://channel9.msdn.com/Events/GoingNative/2013 (especially Stroustrup's talk).
The short answer is no, assuming "modern C++" is >= c++11
The long answer is that wasn't always the case and trying to restructure a large project is almost always hard. The way we think about problems is constrained by the tools we have to solve them. There are many cases when doing such refactoring when it simply makes more sense to use pointers than try to re-express basic logic to be class and smart pointer friendly. I think it's less of a case where smart pointers are over-used and more of a case when classes are under used. YMMV ;-)
Of course there are use cases for raw pointers in modern C++:
interfaces that must be compile-able as pure C (although the implementation itself may make use of those C++ features, that are not also C features, like classes, or smart-pointers)
code that is extremely low level, so low level, that even the simplest smart-pointer proves as being to heavy-weight
Of course those are rather rare cases and for by far the most use cases of pointers smart pointers should be just fine for new code, BUT:
If the existing code works fine with raw pointers, why invest time to rewrite it and risk to add bugs when converting it to a smart-pointer using version?
Don't refactor code, that is working fine, just because the new code better follows modern programming-standards. These programming standards are not existing for their own sake, but to make working with some code easier, so don't do refactoring, which will cost you more time than they can save you in the future.
That means: If it will cost you more time to check, which of those pointers can be safely converted into smart-pointers and which can't and to hunt the bugs, that your refactoring may have introduced, than you will be able to save on future maintenance work due to the refactoring, then simply don't refactor and let it stay as it is.
If the refactoring will save more time than it costs for only some parts of the code base, then consider to only refactor those parts of the code base.
I have a private field
std::map<std::string, std::multiset<GraphObject*>>* the_Map;
How can I allocate memory for it and insert a GraphObject?
Do I have to use the new operator?
the_Map = new map<string,multiset<GraphObject*>>;
And how can I insert a new GraphObject?
It's part of a datastructure and I really need a pointer to a map.
How can I allocate memory for it and insert a GraphObject?
It doesn't want to be a pointer at all; just make the map itself a member of the class and memory allocation will happen automatically.
Correctly inserting an object is rather fiddly, since you're storing pointers there too. If it doesn't need to be a pointer, then storing objects would make your life much easier. If it really does have to be a pointer (e.g. because GraphObject is a polymorphic base class), I would recommend storing smart pointers: std::unique_ptr, or std::tr1::shared_ptr or boost::shared_ptr if you're stuck in the past.
If you really, really need to use raw pointers for some insane reason, then the closest you can get to an exception-safe insertion is probably:
GraphObject * object = new Whatever(...);
try {
the_Map[key].insert(object);
} catch(...) {
delete object;
throw;
}
or if you don't care about the possiblity of memory leaks on insertion failure:
the_Map[key].insert(new Whatever(...));
Also don't forget to delete each object when you remove it; that won't happen automatically.
I really need a pointer to a map.
No you don't. But if you really believe you do, and want to ignore everyone's advice not to, then you'll need an actual map to point to. I would recommend that you make this map a member of the class, so that its lifetime is managed automatically.
If you really want to make life difficult for whoever maintains the code, then I suppose you could allocate one with new. In that case, remember to delete it when you've finished with it; probably in the class destructor. And if you do that, remember the Rule of Three and implement or delete the copy constructor and copy-assignment operator, since the default implementations will do the wrong thing.
Why you're storing a ::std:multiset of GraphObject *'s is a bit obscure, but lets roll with that.
This is an answer that is really trivially answered by documentation, but there is no question too dumb for StackOverflow, so...
the_Map = new map<string,multiset<GraphObject*>>;
That is indeed how you allocate memory for your map. It's generally not a good idea to have bare pointers to things lying around, but you insisted, and that's how you do it. That means you will have to remember to delete it at some point as well. And you will have to make sure that the copy construct of the class that holds the pointer does the right thing (and said right thing will be fairly complicated).
You have an interesting problem now. You are storing a multiset in each map entry. Fortunately this multiset will automatically be created and initialized to empty when a previously unknown key is accessed. OTOH, your use of bare pointers means that you have an exception safety problem. It's possible to leak memory if an exception is thrown anywhere along the way. So you have to catch any exceptions and clean up your object:
GraphObject *tmp = new GraphObject;
try {
(*the_Map)[key].insert(tmp);
} catch (...) {
delete tmp;
throw;
}
The fact your question is so basic makes me question your assertions about needing to use pointers. And I really wonder if you wouldn't rather have a multimap rather than a map from string -> multiset. But, you're adamant about the general form of your data structure. So the above is how you'd use it.
I'll also say that this data structure's copious use of bare pointers is a pretty bad idea. You'll have to write a pretty sophisticated functions to properly deconstruct or copy the whole mess.
Edit: sigh Coding at 4am on a data structure I would never create myself led me to write some very stupid code. The current version is much better. Though this answer is really much better than mine.
In brief, my question is about member variables as pointers in unmanaged C++.
In java or c#, we have "advanced pointer". In fact, we can't aware the "pointer" in them. We usually initialize the member of a class like this:
member = new Member();
or
member = null;
But in c++, it becomes more confusing. I have seen many styles: using new, or leave the member variable in stack.
In my point of view, using boost::shared_ptr seems friendly, but in boost itself source code there are news everywhere. It's the matter of efficiency,isn't it?
Is there a guildline like "try your best to avoid new" or something?
EDIT
I realize it's not proper to say "leave them in stack", here's a more proper way to say: when i need an object to be my member variable, should i prefer a object than a object*?
The Boost source code is not a good example for how you should write your source code. The Boost libraries are designed to wrap up all the tedious, difficult, and error-prone code so that you don't have to worry about it in your code.
Your best bet is to follow two general rules in your code:
Don't use pointers where you don't need to use pointers
Where you do need to use pointers, use smart pointers (like shared_ptr or scoped_ptr)
Yes, there is a guideline - only use dynamic allocation when you must. A lot of the time yo can and should be using values, not pointers. For example, you should almost always be using:
vector <string> v;
rather than:
vector <string *> v;
and allocating the strings dynamically.
Certainly it won't kill you if you do a single new in the constructor, and a single delete in the destructor. In a simple case like that, using smart pointers is just pointless overhead.
If you go more complicated, or if you are paranoid about exception safety, smart pointers may very well be a good idea.
The guide to the language by Stroustrup:
Scott Meyers's triple are quite useful: Effective C++, More Effective C++, and
Effective STL.
Also see these questions:
- https://stackoverflow.com/questions/155762/best-c-resource
- Java FAQ equivalent of C++ FAQ lite?
- C++ : handle resources if constructors may throw exceptions (Reference to FAQ 17.4]
- What C++ pitfalls should I avoid?
- New to C++. Question about constant pointers
The benefit of using shared_ptr is that it is a "smart pointer" that does not require an explicit delete to free the memory. Otherwise, if you use new you will have to explicitly call delete to free the allocated memory once the object is no longer required.
In C++ it is a matter of choice to the developer. There is more power but also more responsibility that goes with it.
Example:
A class that declares an object with internal storage of arbitrary size.
If you design this class to allocate worst case storage at instantiation you can avoid pointers altogether. But the cost is heavy in terms of memory usage for the average case.
If you design the class to allocate memory based on its needs you might choose to use pointers. Then each instance will take only what it needs from the heap. But you must use care to avoid pointer bugs.
If you design the class to allocate memory based on its needs you might still be able to avoid pointers using abstractions for the memory (i.e. auto_ptr or a custom buffer scheme, etc.).
So a guideline might be to explore the options available before resorting to naked pointers in application code. The balance might be different for library code since it will be more limited in scope, possibly more performance sensitive, and (hopefully) better tested.
You may want to use the C++ STL class "autoptr" to take care of managing your memory.
Also, in C++, if it is a member variable, it doesn't have to be a pointer.
class MyClass
{
MyClass();
MyMember a;
MyMember* b;
std::auto_ptr<MyMember> c;
}
MyClass::MyClass()
{
// constructer
// a is now instantiated -- I don't have to do anything
b = new MyMember(); // I'll have to delete it in the destructor
c.reset(new MyMember()); // I won't have to delete it in the destructor
}