C++17 is so full of good stuff I'm considering beta compilers just to get it. Soon Python and Ruby won't have any advantages left in writing beautiful, clear, correct, bug-free, and easy to read code and C++ will still run 200x faster.
C++17 is so full of good stuff I'm considering beta compilers just to get it. Soon Python and Ruby won't have any advantages left in writing beautiful, clear, correct, bug-free, and easy to read code and C++ will still run 200x faster.
Structured bindings are going to be amazing! Yea we didn't get modules, but I for one am psyched about this feature alone.
If only they were faster to upgrade compilers at work...
Come on, it's not like they've added garbage collection.
Then with RAII you can clean up any kind of resource. Most languages have pretty rudimentary tools for closing files and worse for releasing mutexes. These tasks are almost easy to get right in modern C++.
int main() {
with_open_file_for_writing("foo.dat", [](FILE* fp) {
fprintf(fp, "old style I/O, automatically closed\n");
});
return 0;
}Firstly, what exactly is the difference between make_unique and plain old unique_ptr? Why do I need to include a separate template to use the former?
A related issue I faced today. Say I want to create a std::vector of objects. From what I understand, I have three options.
1) Use raw pointers, but be sure to cleanup using delete.
2) Use shared_ptr, which will ensure that your object is safely deleted once no one is referencing it.
3) Create a stack allocated object, then push that onto the vector. The vector will create a shallow copy of the object, and the original copy will be deleted at the end of the current scope.
In this scenario, I wouldn't be able to use unique_ptr, because that would mean that both the vector and the local scope have pointers to that object. Am I correct?
Are there other options for achieving this that I don't know of? Also, which one is the best approach for the general case? I ended up using shared_ptr and it seems to be working fine... I think.
I think technically you could use unique_ptr and transfer ownership (move) when pushing into the vector, but the underlying "bad pattern" here is that you almost never want to have a vector of (smart) pointers. The vector should own the objects directly.
make_unique is just a convenience function for creating a unique_ptr without having to write "new" yourself. It returns a unique_ptr.
Vectors already own their contents, so there is no need to use unique_ptr here. The objects will be allocated on the heap either way, and you don't need a stack object either. Just push or emplace the object into your vector and be done with it. When the vector is deleted, so will its contents, automatically.
Is there any overhead (e.g., copying or moving), or potential for memory leaks?
But don't use new. Just push/emplace it into the vector. Perhaps ask more on stackoverflow.
> The objects will be allocated on the heap either way, and you don't need a stack object either. Just push or emplace the object into your vector and be done with it. When the vector is deleted, so will its contents, automatically
I guess what you mean to say is that emplace_back will do the allocation and lifetime management. But using push_back on a stack-allocated object is going to result in a copy.
push_back with a stack object will copy the object, yes. Emplace_back with a stack object will also, they are not much different. But if you emplace by creating the object inside the emplace call itself, then there is no copy.
see the examples here:
http://en.cppreference.com/w/cpp/container/vector/emplace_ba...
The make_unique function uses variadic templates to take the arguments to your constructor:
auto oldway = std::unique_ptr<Foo>(new Foo(1, 2));
auto newway = std::make_unique<Foo>(1, 2);
The new way has the small virtue of eliminating one more place where you ever need to call new. However, it also offers the library writer more possibilities in the internal implementation. For instance, they can nest your type in another struct for accounting purposes without copying or additional dereferencing. However the second advantage is more relevant to shared_ptr, which is probably why C++11 had make_shared, but not make_unique (added in C++14).> I wouldn't be able to use unique_ptr, because that would mean that both the vector and the local scope have pointers to that object.
Yeah, if you're using unique_ptr, the pointer is uniquely owned in at most one place at a time. For your situation, I think the vector should probably own the objects, and you borrow them with references, iterators, or pointers (via the get() method). Be wary of holding on to those references though (the Rust fans will be quick to point out the dangers here).
A fourth option, which you should consider unless your objects are expensive to copy, is to make your objects copyable and not use unique_ptr or shared_ptr at all. I think it's much simpler to reason about objects as values than it is to reason about objects as smart pointers or (dumb) references.
> I ended up using shared_ptr and it seems to be working fine... I think.
Go with what works for you, but shared_ptr makes additional promises about thread safety and interactions with weak_ptr that increase its runtime costs. I wish shared_ptr was simple by default and that there was yet another smart pointer type for when you need those additional features.
// definition
foo(std::unique_ptr<bar>, std::unique_ptr<baz>);
// call
foo(std::unique_ptr<bar>(new bar), std::unique_ptr<baz>(new baz));
the only guarantee is that `new foo` and `new bar` will occur before the corresponding shared_ptr constructor, and all of them will occur before the call to foo. This means that the following is a valid sequence:1. new foo 2. new bar 3. unique_ptr ...
Now, if constructor of bar throws, you've leaked foo.
With make_unique, construction and smart pointer acquisition is a single atomic operation - if it throws, everything gets cleaned up.
The clever combination of declarative management for common cases and reference counting for complicated cases looks like the winner in the long run.
You'd have to elaborate on that an awful lot to be at all persuasive.
> Rust and Swift
You were comparing C++ to Python and Ruby. We're talking two different paradigms here.
Although, there are conservative GCs for C that replace malloc () and make fre () a nop, they cannot release all memory properly due to C semantics.
Library types like std::shared_ptr don't really count to say that a language has a GC, because their use, specially their correct use, is not enforced by the compiler.
https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...
Reference counting is definitely a method of garbage collection.
GC is an abstraction that can work well but can also interfere with how a developer thinks.
Yep, this is a big issue.
Another good example is copying arrays of primitive types with for loops instead of using intrisics like System.arrayCopy().
Or using lists instead of arrays.
Sure there are many situations where there is no another way other than step out of the JVM into C++, but many could be avoided with better code as well.
So if your program allocated less than available, doing nothing would be a valid GC strategy as your program never hit an upper bound in what it can allocate.
I found that an interesting way to think about the problem because it's more concerned with what GC enables instead of what it strictly does. The former is always the same, no matter the GC implementation, but the latter can vary considerably (doing nothing, reference counting, mark-and-sweep, full concurrent and compacting GC, ...).
Interestingly, this is also the description of Virtual Memory. https://en.wikipedia.org/wiki/Virtual_memory
Chapter 5.
One of the best CS references in GC algorithms.
I can post links to 70's papers if you wish, specially ones related to Lisp research.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n267...
Also, there are the C++/CLI and C++/CX that support GC at language level.
Now std::*_ptr<> types don't count to make the language GC, because their use is not enforced by the compiler.
Then you also shouldn't say that Swift is garbage collected.
C++ language definition doesn't give any special treatment tostd::*_ptr<> types regarding compiler semantics. They could be be something else.
We're talking about garbage-collected languages (and "language" traditionally includes the standard library), not garbage-collected-only languages.
I mean, by your definition, C# also doesn't count, because it has unmanaged pointers in it.
In C#, GC is part of the language semantics and its interaction with unmanaged pointers is well defined in the language semantics standard, including how the memory is pinned when unmanaged pointers need to access GC allocated memory.
If reference counting is a kind of GC, and the standard library offers reference counting, then the language offers a kind of GC - same as if the language itself had a built-in refcounted pointer. There's simply no practical difference here.
It only makes sense to talk like that, if the language semantics define a relationship between the language and library requiring the library to always exist as a form of runtime and how the use of that runtime relates to language constructs.
If I can just throw away the library and replace it by something else where those types aren't available and still make use of 100% of the language features, this relationship doesn't exist.
There's a single document defining what is ISO C++. It defines both the language and the standard library. Therefore, to "write in C++", by default, means to write code that uses and relies upon both the language semantics and the standard library functionality. Which means that std::shared_ptr etc is readily available, and is the standard way to use refcounting-based GC in C++.
Hence, ISO C++ is a language with optional refcounting-based GC.
See page 6, remark 7 in 'Uniprocessor garbage collection techniques', Paul Wilson:
http://scholarworks.rit.edu/cgi/viewcontent.cgi?article=1322...
Exaggerated, I know, but it's not like your post was particularly nuanced.
Reference counting is safe with a DAG (not just a tree), but I get your point. For the times I've needed an arbitrary graph data structure, I used an adjacency matrix to store it.
[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#reference-c...
[2] https://github.com/duneroadrunner/SaferCPlusPlus#asynchronou...
I mean we have destructors which handle so much more than garbage memory.
Close files, release mutexes, close sockets, cleanup thread pools, manage the lifetime of anything. One time I opened a web browser in the constructor and closed it in the destructor, and I had full confidence that no matter what crap happened in the middle my app never leaked whole browsers.
So it's totally doable in library without cost to those that do not need it.
Does that mean C++17 will finally get support for the generator pattern?
Boost.asio provides stackless generators [1] implemented purely in C++, by (ab)using the preprocessor and the switch statement.
[1] http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/ove...
But there will be books, and good ones. Next year probably. The compilers aren't even ready yet.