Does it make a sense to use 'new' when creating std::set? - c++

Explain, please, me next things.
#include <iostream>
#include <set>
int main() {
std::set<int>* a = new std::set<int>;
a->insert(2);
a->insert(5);
for ( std::set<int>::iterator it = a->begin(); it != a->end(); it++ ) {
std::cout << *it << std::endl;
}
std::cout << "Deleting a....." << std::endl;
delete a;
for ( std::set<int>::iterator it = a->begin(); it != a->end(); it++ ) {
std::cout << *it << std::endl;
}
return 0;
}
$ g++ test6.cpp && a
2
5
Deleting a.....
2
5
3544585
Does it make any sense to use operator new creating std::set? As I read in manuals, std::set has its own Allocator object, which is responsible for dynamic memory allocating using operator new. But interesting to know experienced members point of view.
Why after deallocating memory using delete a members of std::set are still avaliable and have values 2 and 5 like before delete a. And what is the right way to delete member a.
Thanks.

Watch this part of Stroudstrup's talk at Going Native 2013
1) No, you can just create a local variable a and let it be released at the end of the function through normal control flow
std::set<int> a;
a.insert(2);
a.insert(5);
2) You're getting lucky. It's undefined behavior to access memory that has been released. Run this code through valgrind and you'll see errors.
int *ip = new int{1};
delete ip;
int a = *ip; // NOT SAFE, maybe 1, maybe 24630751, maybe crash

No, the standard library has memory management functionality included, so the programmer does not have to concern themselves with this.
The reason you are still seeing sensible values output after the delete, is because your PC has not written new values over the memory spaces yet. This is why attempting to access memory after it is deleted is under the "undefined behavior" umbrella.

Related

How do I create an array of objects?

I only know Java, and I am learning how to do c++ right now. I currently have an object called "node". I want to make an array of those elements in a different class, and I have to perform many operations on this array. Because of this, I am trying to declare a global array variable that gets initialized in my constructor. In Java, this would've been done by
ObjectName[] variableName = new ObjectName[size];
but I am not sure how to do it in c++. I've tried declaring it similar to how I declared the other global arrays, with
Node* nodes;
and then in my constructor:
nodes = new Node[size]
but I got a bunch of compiler errors. How am I supposed to do this? This is only my second week of coding in c++, so try to keep answers basic.
In C++ you use vector more often than array. You also distinguish between creating objects on the stack and on the heap (you already mentioned that concept; in C++ you are more actively involved in thinking about that).
You also may want to pay attention which C++ Standard you are using. Some concepts are not available in older standards. I tried to mention some in the example code below.
When dealing with arrays in C/C++ you should understand the notion of pointers, which I believe is the probable cause of your confusion. new creates an object on the heap and returns a pointer. When creating an array, then the returned pointer points to the first element.
Avoid new if you can. In newer C++ standards there are better concepts of smart pointers (e.g. std::unique_ptr<...>); I will not dive into that since you are just beginning. Be patient with learning C++, I am sure you will succeed, it takes time really.
#include <iostream>
#include <array>
#include <vector>
struct Node {
std::string name = "node";
};
int main() {
const size_t size = 10;
// you can create it on the stack
// will be deleted when leaving the block/scope
Node nodes1[size];
nodes1[0].name = "first node1";
std::cout << nodes1[0].name << std::endl;
// you can create it on the heap
// you have to delete the objects yourself then
Node *nodes2 = new Node[size];
nodes2[0].name = "first node2";
std::cout << nodes2[0].name << std::endl;
// in C++ 11 and later you can use std::array<...>
// you have to include the header <array> for that
std::array<Node, size> nodes3;
nodes3[0].name = "first node3";
std::cout << nodes3[0].name << std::endl;
// in C++ you use array "seldom"
// instead you use the containers quite a lot as far as I have learned
// e.g. you can include <vector>; can be used like an array
std::vector<Node> nodes4(size);
nodes4[0].name = "first node4";
std::cout << nodes4[0].name << std::endl;
// you can iterate over a vector like you know it from an array
for (size_t i = 0; i < nodes4.size(); ++i) {
if (i == 0) {
std::cout << nodes4[i].name << std::endl;
}
}
// in C++ you will soon learn about iterators too
for (auto iter = nodes4.begin(); iter != nodes4.end(); iter++) {
if (iter == nodes4.begin()) {
std::cout << iter->name << std::endl;
}
}
return 0;
}
How do I create an array of objects?
Given a type named ObjectName, you can define an array variable with name variableName and a compile time constant size size like this:
ObjectName variableName[size]{};

Replacing shared_ptr elements in std::vector

I have a vector of shared_ptrs as below.
std::vector<std::shared_ptr<SharedThing>> things;
Now let's say I push a number of shared_ptrs onto the vector and each element now has a reference count of 1.
When I need to replace one of those elements with a new shared_ptr I want the old shared_ptr to go out of scope. Will regular element assignment achieve this or will it just copy the shared_ptr contents. For example:
things.at(0) = new_shared_ptr;
Will this decrement the reference count of things.at(0) and increment the count of new_shared_ptr?
When I need to replace one of those elements with a new shared_ptr I
want the old shared_ptr to go out of scope. Will regular element
assignment achieve this?
The shared pointer in the vector won't go out of scope,
but it will replace the managed object with the new one given.
Calling:
things.at(0) = new_shared_ptr;
will preserve the count at 1.
Here is an easy way to observe this behaviour:
#include <iostream>
#include <vector>
#include <memory>
int main(){
//vector with a shared pointer
std::vector<std::shared_ptr<int>> things;
things.push_back(std::make_shared<int>(1));
//prints 1
std::cout << things.at(0).use_count() << '\n';
//assign a new value
things.at(0) = std::make_shared<int>(2);
//still prints 1
std::cout << things.at(0).use_count() << '\n';
}
Although not a part of your question, it is often advised to use make_shared instead of a new.
Yes, basically you are right.
To be more accurate, the reference count of previous shared_ptr at(0) will be decremented. And then you assign it with a new shared_ptr, which may have the count 1. Looks like the reference count at(0) is the same, but it changed and changed back.
You can verify it by std::shared_ptr::use_cout()
For more details, we can debug into the STL, when
things.at(0) = new_shared_ptr;
include/c++/4.8.3/bits/shared_ptr_base.h:556
__shared_count&
operator=(const __shared_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
{
if (__tmp != 0)
__tmp->_M_add_ref_copy();
if (_M_pi != 0)
_M_pi->_M_release();
_M_pi = __tmp;
}
return *this;
}
The new one _M_add_ref_copy(), then previous one _M_release(), which will decrease the _M_use_count by 1.

Expression must have a pointer type error

I have read the other similar posts, but still haven't found a way to solve my coding problem.
Here is the code:
void Foo(vector<Name> &obj){
vector<Name> *temp = 0;
temp = new vector<Name>;
if (!temp){
std::cout << "temp Allocation Error!" << std::endl;
exit(1);
}
temp->push_back(obj[n]);
std::cout << temp[0]->member_function() << std::endl;
}
Foo is a universal function.
I have a function Foo that takes a reference to a vector container. Within Foo there is a dynamic vector called temp.
I use push_back() to insert an obj into the temporary vector.
Then I wish to access that obj stored in the temporary vector in order to access its member function.
However this is where the compiler says that "expression must have pointer type".
Could somebody please explain how to rewrite this line of code.
std::cout << temp[0]->member_function() << std::endl;
temp[0]->member_function()
This treats temp as if it were an array of pointers-to-vector, which it's not.
You need to dereference temp before performing array subscripting on the result:
(*temp)[0].member_function()
Honestly, though, dynamic allocation here is pointless and is giving you a memory leak right now.
You have a vector of Name objects, and not Name*, but you use the "->" operator instead of "." which is what the compiler is telling you.
You should either try:
std::cout << (*temp)[0].member_function() << std::endl;
or make the vector elements Name*.
temp[0]->member_function()
would be correct if temp were a vector of pointers, but it isn't – it's a pointer to one vector.
And you can't use -> with a vector.
(It is equivalent to (*temp)->member_function().)
You can say
(*temp)[0].member_function()
but the better solution is usually to avoid dynamic allocation completely:
vector<Name> temp;
temp.push_back(obj[n]);
std::cout << temp[0].member_function() << std::endl;

C++ Vector: push_back Objects vs push_back Pointers performance

I'm testing performance difference between pushing back Objects vs pushing back object Pointers to Vector in C++.
I've read in Stackoverflow and other articles that you should avoid pushing back pointers unless you must do so...
However, I realized that there is a HUGE performance gain for pushing back Pointers,,,
This is a simple test I ran:
tstart = chrono::system_clock::now();
vector<MyObject> VectorOfObjects;
for (int i=0; i<10000; i++) {
MyObject x("test");
VectorOfObjects.push_back(x);
}
tend = chrono::system_clock::now();
tt = tend-tstart;
cout << "Pushback Object: " << tt.count()*1000 << " Milliseconds\n" << endl;
tstart = chrono::system_clock::now();
vector<MyObject *> VectorOfPointers;
for (int i=0; i<10000; i++) {
VectorOfPointers.push_back(new MyObject("test"));
}
tend = chrono::system_clock::now();
tt = tend-tstart;
cout << "Pushback Pointers: " << tt.count()*1000 << " Milliseconds\n" << endl;
The result is actually pretty surprising:
Pushback Objects: 989 Milliseconds
Pushback Pointers: 280 Milliseconds
As you can see, pushing back pointers is 3~4 times faster than pushing back objects! which is a huge performance difference, especially when dealing with large volume of data.
So my question is: WHY NOT USE Vector of Pointers??
Answers to almost every post on Stackoverflow regarding similar question says Avoid Vector of Pointers..
I know memory leakage might be a problem,, but we can always use Smart Pointers,, and even manually deleting the pointers at destruction is not that difficult..
I'm also curious about the cause of this performance difference..
Thanks
UPDATE:
Actually I tested on ideone .... and here, pushback objects is Faster!!!
In Visual Studio,, pushing back Objects was Wayyy slower..
Why is this...??
To be fair, when measuring your code you should account for deallocation of all those pointers. A sample code would read as :
#include <chrono>
#include <string>
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
// 1. A way to easily measure elapsed time -------------------
template<typename TimeT = std::chrono::milliseconds>
struct measure
{
template<typename F>
static typename TimeT::rep execution(F const &func)
{
auto start = std::chrono::system_clock::now();
func();
auto duration = std::chrono::duration_cast< TimeT>(
std::chrono::system_clock::now() - start);
return duration.count();
}
};
// -----------------------------------------------------------
// 2. MyObject -----------------------------------------------
struct MyObject {
string mem;
MyObject(const char *text) : mem(text) {};
};
// -----------------------------------------------------------
int main()
{
vector<MyObject> VectorOfObjects;
vector<MyObject *> VectorOfPointers;
cout << "Pushback Object: " << measure<>::execution([&]()
{
for (int i = 0; i < 100000; i++) {
MyObject x("test");
VectorOfObjects.push_back(x);
}
}) << endl;
cout << "Pushback Pointers: " << measure<>::execution([&]()
{
for (int i = 0; i < 100000; i++)
VectorOfPointers.push_back(new MyObject("test"));
for (auto &item : VectorOfPointers)
delete item;
}) << endl;
return 0;
}
and when compiled with
g++ -std=c++11 -O3 -march=native -Wall -pedantic
the results are (I'm using +1 order of magnitude in the for loops) :
Pushback Object: 20
Pushback Pointers: 32
If you used
VectorOfObjects.emplace_back("test");
The duration of the VectorOfObjects modification would drop to 18
If you preallocated both vectors
vector<MyObject> VectorOfObjects;
VectorOfObjects.reserve(100000);
vector<MyObject *> VectorOfPointers;
VectorOfPointers.reserve(100000);
the result would be 17-34 (for the vector of objects again)
If you use a vector of unique pointers then the results are similar
vector<unique_ptr<MyObject>> VectorOfPointers;
note that I'm limiting the scope of the vectors to explicitly account for the destruction of the smart pointers
Other choices would include boost's pointer containers in which case the related data structure would be a pointer vector
I prefer to use shared pointers opposed to regular pointers and I always use them when I can.
I use shared pointers with vectors when dealing with the vector changing a lot.
You should avoid regular pointers when dealing with vectors, as they need to be manually destructed and will just cause memory leaks.
So to answer your question...
Look into the shared_ptr library and use those instead here is a link http://www.cplusplus.com/reference/memory/shared_ptr/
hope this answers your question
The way your sample code is written, there is definitly a memory leak problem. Agreed that you can fix that problem by doing a deletes.
It can be done but it is just cumbersome. If you take care of things like memory leaks, it is fine.
The root issue for performance here is that there are copies of objects being made. You create an object. When you add it to the vector. It creates a new object and copies yours using the copy constructor.
C++11 improves the situation a bit by introducing emplace_back(). So if you are using C++11, you may be able to get the same performance by using emplace.

sending back a vector from a function

How to translate properly the following Java code to C++?
Vector v;
v = getLargeVector();
...
Vector getLargeVector() {
Vector v2 = new Vector();
// fill v2
return v2;
}
So here v is a reference. The function creates a new Vector object and returns a reference to it. Nice and clean.
However, let's see the following C++ mirror-translation:
vector<int> v;
v = getLargeVector();
...
vector<int> getLargeVector() {
vector<int> v2;
// fill v2
return v2;
}
Now v is a vector object, and if I understand correctly, v = getLargeVector() will copy all the elements from the vector returned by the function to v, which can be expensive. Furthermore, v2 is created on the stack and returning it will result in another copy (but as I know modern compilers can optimize it out).
Currently this is what I do:
vector<int> v;
getLargeVector(v);
...
void getLargeVector(vector<int>& vec) {
// fill vec
}
But I don't find it an elegant solution.
So my question is: what is the best practice to do it (by avoiding unnecessary copy operations)? If possible, I'd like to avoid normal pointers. I've never used smart pointers so far, I don't know if they could help here.
Most C++ compilers implement return value optimization which means you can efficiently return a class from a function without the overhead of copying all the objects.
I would also recommend that you write:
vector<int> v(getLargeVector());
So that you copy construct the object instead of default construct and then operator assign to it.
void getLargeVector(vector<int>& vec) {
// fill the vector
}
Is a better approach for now. With c++0x , the problem with the first approach would go by making use of move operations instead copy operations.
RVO can be relied upon to make this code simple to write, but relying RVO can also bite you. RVO is a compiler-dependent feature, but more importantly an RVO-capable compiler can disable RVO depending on the code itself. For example, if you were to write:
MyBigObject Gimme(bool condition)
{
if( condition )
return MyBigObject( oneSetOfValues );
else
return MyBigObject( anotherSetOfValues );
}
...then even an RVO-capable compiler won't be able to optimize here. There are many other conditions under which the compiler won't be able to optimize, and so by my reckoning any code that by design relies on RVO for performance or functionality smells.
If you buy in to the idea that one function should have one job (I only sorta do), then your dilema as to how to return a populated vector becomes much simpler when you realize that your code is broken at the design level. Your function really does two jobs: it instantiates the vector, then it fills it in. Even with all this pedantary aside, however, a more generic & reliable solution exists than to rely on RVO. Simply write a function that populates an arbitrary vector. For example:
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
template<typename Iter> Iter PopulateVector(Iter it, size_t howMany)
{
for( size_t n = 0; n < howMany; ++n )
{
*(it++) = n;
}
return it;
}
int main()
{
vector<int> ints;
PopulateVector(back_inserter(ints), 42);
cout << "The vector has " << ints.size() << " elements" << endl << "and they are..." << endl;
copy(ints.begin(), ints.end(), ostream_iterator<int>(cout, " "));
cout << endl << endl;
static const size_t numOtherInts = 42;
int otherInts[numOtherInts] = {0};
PopulateVector(&otherInts[0], numOtherInts);
cout << "The other vector has " << numOtherInts << " elements" << endl << "and they are..." << endl;
copy(&otherInts[0], &otherInts[numOtherInts], ostream_iterator<int>(cout, " "));
return 0;
}
Why would you like to avoid normal pointers? Is it because you don't want to worry about memory management, or is it because you are not familiar with pointer syntax?
If you don't want to worry about memory management, then a smart pointer is the best approach. If you are uncomfortable with pointer syntax, then use references.
You have the best solution. Pass by reference is the way to handle that situation.
Sounds like you could do this with a class... but this could be unnecessary.
#include <vector>
using std::vector;
class MySpecialArray
{
vector<int> v;
public:
MySpecialArray()
{
//fill v
}
vector<int> const * getLargeVector()
{
return &v;
}
};