I have two sample classes Sample and Hello
The Hello has a map which contains a map in heap, that map has Class Sample's object in it's value type.
class Hello
{
public:
map<int,Sample>* samMap;
};
And my function has a code like this
Hello * h = new Hello;
{
h->samMap = new map<int,Sample>;
for(int i=0 ; i<100000;i++)
{
Sample se;
se.a = i*2;
se.b = i*5;
se.vecInt = new vector<int>;
se.vecInt->push_back(i+2);
h->samMap->insert(make_pair(i,se));
}
}
map<int,Sample>::iterator ss = h->samMap->find(50);
if(ss != h->samMap->end())
{
cout << " Value : " << ss->second.a << " " << ss->second.b << endl;
for(int s=0; s<ss->second.vecInt->size(); s++)
{
cout << ss->second.vecInt->at(s) << endl;
}
}
From the above code, the Sample object is declared and used inside a block. Once the control comes out of block the stack object have to get cleared.
But still i can iterate the map and get the Sample's objects outside the for loop without any access violation exception.How is that possible? While inserting the object to container a new copy of object is inserted ?
Yes. Because you're not storing a pointer or reference, a copy is made when you add it to the map.
Of course, if class Sample has a destructor to delete vecInt, it will also need a copy constructor; otherwise the pointer in the map's copy becomes invalid when the local "original" goes out of scope.
The correct way here is to avoid deep copies and use memory management support from the standard library: most usages of new are a sign of poor design. For example (I'm guessing a bit about the guts of Sample)
class Sample
{
int a=0, b=0;
std::vector<int> vecint; // not a pointer, but data member
public:
Sample(int _a, int _b) // construct sample with empty vecint
: a(_a), b(_b) {}
void add(int x) // add to vecint
{ vecint.push_back(x); }
};
struct Hello
{
std::map<int,Sample> samMap;
};
Hello makeHello()
{
Hello hello;
for(int i=0; i<100000; ++i)
{
auto r = hello.samMap.emplace(std::piecewise_construct,
std::forward_as_tuple(i),
std::forward_as_tuple(i*2,i*5));
if(!r.second)
throw std::runtime_error("couldn't insert new Sample for key '"+std::to_string(i)+"'");
r.first->second.add(i+2); // add to inserted Sample
}
return hello;
}
Note: no call to new and, consequently, no call to delete. It's all done under the hood by the standard library containers std::map and std::vector.
See also the documentation for std::map and std::map::emplace.
Related
I have two data types, A and B and I have to store the A instance in B in order to refer the A instance in a B method. Both are instantiated in the main function, so the two variables would live for as long as the program is running.
I don't want to make copies, I want to use something like an old fashioned pointer but also I want to follow (and learn) the modern C++ best practices. So what is the most appropriate type to store the A instance in B? (and why?)
I thought that if I want to use a pointer, the best way with modern C++, is using smart pointers, but references seems easier and lighter, so what is the best practice to refer to a variable created in a scope (for example in the main function) and used in another scope (for example a method of a class that has a pointer to that variable), knowing that the scope where that variable is created lives for as long as the class exists (when the stack is deallocated, it will free both the variable and the object that has the variable reference)?
struct A {};
struct B {
A & a;
B(A & a) : a(a) {}
};
int main() {
A a{};
B b{a};
}
or
#include<memory>
struct A {};
struct B {
std::shared_ptr<A> a;
B(auto a) : a(a) {}
};
int main() {
B b{std::make_shared<A>()};
}
The program I'm making is essentially a bunch of test to learn SDL2, I published the repo here https://github.com/antcolag/prova-sdl, B is the App class and A is the EventHandler class instantiated inside the main function.
As #πάντα-ῥεῖ noticed in my particular case the only reasonable way is with smart pointer, because I'm trying to use std::thread and std::atomic, but in a most general case what is the best way to replace the old C style pointers, with a more modern approach, when a variable is allocated in the stack, used by some other object and then deallocated from the stack together with the object?
If i understood the problem, you want to move the instance to a different "owner", with A a; it is posible but it requires a memcpy() if the scope of the instance is deleted. The most easy solution is to contain it in a shared scope, that is bad because it can be a global scope, the next best thing is to pass the reference to the owner (the structure that contains the data). At the end this are cheap solutions if they are applied over and over, modern c++ has a lot of tools for memory control / flow; most of those are pointer based because the data pointer copy is trivial, note that only in combination with std::atomic or a similar lib is suitable for multithreading.
This example shows how a data pointer can be moved and used without any fancy c++, a small note on the pointer idea, in the example the pointer address is not changing as long as it is not deleted, any reference made will persist even if ref_objs order is changed, the data is "on the wild" and the pointer is a number.
#include <iostream>
struct Object {
int num = 69;
};
struct Container {
// Better to use std::vector but
// this shows better what it does
// Olso can be replaced with
// Object * ref_objs [n] if n is fixt
Object ** ref_objs;
uint32_t n_obj;
uint32_t n_obj_max;
void provision_for(uint32_t res_len){
// To initialize data is better to use
// use a method insted of the constructor;
// This alocates n spaces of obj pointers
ref_objs = new Object * [res_len];
n_obj_max = res_len;
n_obj = 0;
}
void clear_all(){
uint32_t i;
for (i=0; i < n_obj; i++){
delete ref_objs[i];
}
delete [] ref_objs;
n_obj = 0;
}
Object * add_obj(){
Object * ret = nullptr;
if (n_obj < n_obj_max){
ref_objs[n_obj] = new Object;
ret = ref_objs[n_obj];
n_obj++;
}
return ret;
}
void del_obj(uint32_t n){
if (n < n_obj - 1){
// keeps them alighned
ref_objs[n] = ref_objs[n_obj];
}
delete ref_objs[n_obj];
n_obj--;
}
int recive_obj(Object * ref){
int res = 1;
if (n_obj < n_obj_max){
ref_objs[n_obj] = ref;
n_obj++;
res = 0;
}
return res;
}
int transfer_to(Container * to, uint32_t item){
int res = 1;
if (to->recive_obj(ref_objs[item]) == 0){
if (item < n_obj - 1){
ref_objs[item] = ref_objs[n_obj - 1];
} else {
ref_objs[item] = nullptr;
}
n_obj --;
res = 0;
}
return res;
}
Object * at (uint32_t at){
return ref_objs[at];
}
Object & operator [](uint32_t at){
// [0] is added to asure the compiler that it
// is a instance and not an array
return ref_objs[at][0];
}
};
int main(void){
Container container_a;
Container container_b;
container_a.provision_for(10);
container_b.provision_for(15);
Object * x = container_a.add_obj();
Object * y = container_a.add_obj();
Object * z = container_b.add_obj();
std::cout << "container_a len -> " << container_a.n_obj << std::endl;
std::cout << "container_b len -> " << container_b.n_obj << std::endl;
y->num = 200;
container_a.transfer_to(&container_b, 0);
container_b[1].num = 400;
std::cout << "container_a obj[0].num -> " << container_a[0].num << std::endl;
std::cout << "container_b obj[0].num -> " << container_b[0].num << std::endl;
std::cout << "container_b obj[1].num -> " << container_b.ref_objs[1]->num << std::endl;
container_a.del_obj(0);
container_a.clear_all();
container_b.clear_all();
return 0;
}
(This example is template suitable, just change all Object with the typename and the instance will be Container<Object> container_a;)
What I am trying to achieve is creating a superclass array of subclass objects.
In this particular test I'm working on, I want to have an animal array that has some dog objs and some cat objs while they maintain their attributes.
#include <iostream>
using namespace std;
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
//MAIN
int main(int argc, char* argv[])
{
animal** test;
animal* p;
for (int i = 0; i < 6; i++)
{
p = new dog;
p++;
}
cout << "\n";
for (int i = 0; i < 6; i++)
{
p = new cat;
p++;
}
cout << "\n";
test = &p;
cout << (*test-7)->get_ID();
return 0;
}
What I've learned so far is that p isn't an array, and it keeps pointing to different memory addresses through the loops.
I cannot do animal** test = new dog[6]; as it is an invalid initialization. Even if that worked I would have trouble cascading another array segment of cat.
This is the output I obtained:
1 2 3 4 5 6
90 91 92 93 94 95
0
The first line is displaying dog IDs being invoked 6 times, and the second line is displaying cat IDs being invoked 6 times. (*test-7)->get_ID();is the last number.
It seems the constructors are being invoked right. However, I have no idea where my pointer is pointing, since I am expecting 91 not 0.
How do I get an animal array that I can access information from each element? For example,
animal** myArray;
{do something}
cout << myArray[2].get_name() << endl << myArray[7].get_ID();
and it outputs
Woof! Corgi
91
One important detail about the animal class: polymorphic types can run into issues when their destructors are called but those destructors are not virtual. It is recommended that you make the destructor of the base class virtual, even if that class itself does not actually need a destructor. In this case, you can tell the compiler that you want the destructor to be virtual but generate a default implementation of it with:
virtual ~animal() = default;
Add the above line in the public: section of your animal class. This ensures that any derived classes that you define later on will get a virtual destructor automatically.
Now to the rest of your code:
p = new dog;
So far, so good. But then this:
p++;
does nothing useful other than making the pointer point to an invalid address. Then in the next iteration, another p = new dog; will be performed. The previous dog object you allocated is now lost forever. You got a so-called "leak".
It seems you expect new to allocate objects an a way that lays them out in memory one after another. That is not the case. new will allocate memory in an unpredictable location. As a result, this:
*test-7
cannot possibly work, as the objects are not laid out in memory the way you expected. What you get instead is an address to some memory location 7 "positions" before the latest allocated object that pretty much certainly does not point to the animal object you were hoping. And when you later dereference that you get undefined behavior. Once that happens, you cannot reason about the results anymore. They can be anything, from seeing wrong text being printed to your program crashing.
If you want an array of animal pointers, you should specifically create one:
animal* animals[12];
This creates an array named animals that contains 12 animal pointers. You can then initialize those pointers:
for (int i = 0; i < 6; i++) {
animals[i] = new dog;
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = new cat;
}
You then just specify the array index of the one you want to access:
cout << animals[0]->get_ID() << '\n'; // first animal
cout << animals[6]->get_ID() << '\n'; // seventh animal
Don't forget to delete the objects after you're done with the array. Since animals is an array, you can use a ranged for loop to delete all objects in it:
for (auto* animal_obj : animals) {
delete animal_obj;
}
However, all this low-level code is quite tedious and error-prone. It's recommended to instead use library facilities that do the allocations and cleanup for you, like std::unique_ptr in this case. As a first step, you can replace your raw animal* pointer with an std::unique_ptr<animal>:
unique_ptr<animal> animals[12];
(Don't forget to #include <memory> in your source file, since std::unique_ptr is provided by that library header.)
Now you've got an array of smart pointers instead of raw pointers. You can initialize that array with:
for (int i = 0; i < 6; i++) {
animals[i] = make_unique<dog>();
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = make_unique<cat>();
}
Now you don't need to delete anything. The smart pointer will do that automatically for you once it goes out of scope (which in this case means once the animals array goes out of scope, which happens when your main() function exits.)
As a second step, you can replace the animals array with an std::vector or an std::array. Which one you choose depends on whether or not you want your array to be able to grow or shrink later on. If you only ever need exactly 12 objects in the array, then std::array will do:
array<unique_ptr<animal>, 12> animals;
(You need to #include <array>.)
Nothing else changes. The for loops stay the same.
std::array is a better choice than a plain array (also known as "built-in array") because it provides a .size() member function that tells you the amount of elements the array can hold. So you don't have to keep track of the number 12 manually. Also, an std::array will not decay to a pointer, like a plain array will do, when you pass it to functions that take an animal* as a parameter. This prevents some common coding bugs. If you wanted to actually get an animal* pointer from an std::array, you can use its .data() member function, which returns a pointer to the first element of the array.
If you want the array to be able to grow or shrink at runtime, rather than have a fixed size that is set at compile time, then you can use an std::vector instead:
vector<unique_ptr<animal>> animals;
(You need to #include <vector>.)
This creates an empty vector that can store elements of type unique_ptr<animal>. To actually add elements to it, you use the .push_back() function of std::vector:
// Add 6 dogs.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<dog>());
}
// Add 6 cats.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<cat>());
}
Instead of push_back() you can use emplace_back() as an optimization, but in this case it doesn't matter much. They key point to keep in mind here is that a vector will automatically grow once you push elements into it. It will do this automatically without you having to manually allocate new elements. This makes writing code easier and less error-prone.
Once the vector goes out of scope (here, when main() returns,) the vector will automatically delete the memory it has allocated to store the elements, and since those elements are smart pointers, they in turn will automatically delete the animal objects they point to.
If you're new to C++, it's important that you get started on the right foot and to follow modern best practices, namely:
Avoid using pointers, new, delete, new[] and delete[].
Instead use smart-pointers (unique_ptr, shared_ptr, but don't use auto_ptr!).
Use the make_ functions instead of new. That way you don't need to worry about delete.
See Advantages of using std::make_unique over new operator
Use std::vector<T> (and std::array<T,N> if you have fixed-size collections) instead of new[] or p** (and never use malloc or calloc directly in C++!)
I note that you should also generally prefer Composition over Inheritance, but with trivial examples like yours it's difficult to demonstrate the concept because a Dog and a Cat "are" Animals.
I also note that when the possible set of subclasses is known at compile-time you should consider using a union-type instead of subclassing because it allows consumers to exhaustively work with returned values without needing to use RTTI or guesswork.
This can be done with using AnAnimal = std::variant<cat,dog>.
Anyway, this is what I came-up with. The class animal, class dog, and class cat code is identical to your posted code (and is located within the // #region comments), but the #include and using statements at the top are different, as is the main method.
Note that my code assumes you have a compiler that complies to the C++14 language spec and STL. Your compiler may default to C++11 or older. The std::make_unique and std::move functions require C++14.
Like so:
#include <iostream>
#include <memory>
#include <vector>
#include <string>
// Containers:
using std::vector;
using std::string;
// Smart pointers:
using std::unique_ptr;
using std::move;
using std::make_unique;
// IO:
using std::cout;
using std::endl;
// #region Original classes
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
// #endregion
int main()
{
// See https://stackoverflow.com/questions/44434706/unique-pointer-to-vector-and-polymorphism
vector<unique_ptr<animal>> menagerie;
// Add 6 dogs:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<dog>() );
}
// Add 6 cats:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<cat>() );
}
// Dump:
for ( auto &animal : menagerie ) {
cout << "Id: " << animal->get_ID() << ", Name: \"" << animal->get_name() << "\"" << endl;
}
return 0;
}
I am making an array of 4 std::list. But when I try to access the array's first list's first A object and call the callMe() method on it I get a weird output.
Now 2 things could have happened:
Either the list was empty.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))).
Details of the above cases:
If no A object was created then I should have got an exception. But I didn't get any exception so I am assuming that an A object was created.
So if an A object was indeed created, then the constructor should have been called.
What am I missing?
#include <iostream>
using namespace std;
class A {
public:
A() {
cout<<"Constructor called"<<endl;
x=20;
}
void callMe();
private:
int x;
};
void A::callMe() {
cout<<"Value of x = "<<x<<endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
(*(arrayOflistOfA[0].begin())).callMe();
}
The output is:
Value of x = 0
but the output should have been:
Constructor called
Value of x = 20
If no A object was created then I should have got an exception.
Not true.
But I didn't get any exception so I am assuming that an A object was created.
Don't assume. Find out. Go to some documentation for begin() and for iterators and discover that you do not get an exception, you get UB.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))). [And] if an A object was indeed created, then the constructor should have been called.
That's right. Clearly you have no elements in the list.
And we know that, because there is no code in your program that adds elements to the list.
Also you should not dynamically allocate containers unless you really, really need to (I've never found a need to).
You aren't actually populating the list with any values. I tested the below code and include a commented explanation.
#include <iostream>
#include <list>
using namespace std;
class A {
public:
A();
void callMe();
private:
int x = 0;
};
A::A()
{
cout << "Constructor called" << endl;
x = 20;
}
void A::callMe() {
cout << "Value of x = " << x << endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
cout << arrayOflistOfA->size() << endl; // As you can see, size is 0 here - you created a list of nulls.
for (int i = 0; i < size; i++)
{
arrayOflistOfA->push_back(A());
}
// The below code demonstrates how to loop through the array once it's populated.
list<A>::iterator it;
for (auto& a : *arrayOflistOfA)
{
a.callMe();
}
return 0;
}
I got the answer to my question. Firstly I tried to run this code on my mac with GNU C++ compiler but when I ran the same code on an iPhone simulator it crashed. So as #PaulMcKenzie mentioned, I was indeed trying to dereference an invalid iterator.
I have a task to create an object Stos which would feature a heap of objects Obiekt, to which I could add things as I please.
In order to make the program better support dynamic arrays I decided to use a Vector.
The whole implementation seems to run perfectly, the returned value is completely off.
Here is an example with code:
class Obiekt {
private:
int id;
public:
Obiekt::Obiekt(int i) {
id = i;
}
void Obiekt::display() {
cout << "This object has id of: " << id << endl;
}
};
class Stos {
private:
vector < Obiekt* > stos;
public:
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
void Stos::display() {
cout << endl << "===HEAP DISPLAY===" << endl;
for (int i = 0; i < stos.size(); i++) {
stos[i]->display();
}
}
};
void Zad1()
{
Obiekt obj1(5);
Obiekt obj2(23);
Stos s1(obj1);
s1.add(obj2);
s1.display();
getchar();
}
And the outcome being:
===HEAP DISPLAY===
This object has id of: -858993460
This object has id of:9805925
I'm not a cpp expert, and believe the issue is related to the stos.push_back(&n) portion, but I can't catch the moment the id gets so distorted.
It's probably a noob question, so sorry for that on start.
Any help would be amazing.
The issue with your code as O'Neil correctly explained is that you're adding the pointer to a copy of the Obiekt object. So basically, you create your object in main, and pass it to the constructor and the .add function in Stos. You then add the pointer to the vector. When the function finishes, the copy that was passed is destroyed and the pointer in your vector is dangling.
There are two ways to fix this:
1 Pass by reference
This is very simple, basically you just add an ampersand to your function parameters. For instance:
void Stos::add(Obiekt &n) {
stos.push_back(&n);
}
This will ensure that the object isn't destroyed at the end of the function
2 Don't use pointers
Another way of getting your problem to work is to avoid using pointers at all. Your vector will actually copy the contents of the Obiekt object into it. For example:
vector < Obiekt > stos; // notice how we define it without the pointer type
...
void Stos::add(Obiekt n) {
stos.push_back(n); // Creates copy which will then contain the correct value
}
The parameters Obiekt n in
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
are temporary copies destroyed immediatly after each call.
You have to use a reference Obiekt & n instead, or better: by pointer Obiekt * n.
I'm reluctant to assert that the objects exist at the time display is called.
Problem(s)
According to GCC's implementation they don't.
They fall out of scope and are immediately destructed. Give "Obiekt" a non-trivial destructor and this behavior becomes obvious:
~Obiekt(){std::cout << "Bye from: " << it << std::endl;}
Secondarily, note that you shouldn't specify the class membership for functions defined within the class itself (no class_name::function_name(parameters), just function_name(parameters) )
Possible Fix
You (might) want to changing "Stos" such that:
Stos(Obiekt &n) {add(n);}
void add(Obiekt &n) {stos.push_back(&n);}
I have a few lines of code and I don't get, why and where the copy constructor is called. Could you explain it to me?
The output is:
CS10
CS99
CC100
Obj10=Obj100
D100
Obj10=Obj99
D99
D10
This is my source code:
#include <iostream>
using namespace std;
class my
{
int m;
public:
my(int i): m(i)
{
cout << "CS" << m << endl;
}
my(const my& c): m(c.m+1)
{
cout << "CC" << m << endl;
}
~my()
{
cout << "D" << m << endl;
}
my& operator=(const my &c)
{
cout << "Obj" << m << "=Obj" << c.m << endl;
return *this;
}
};
my f(my* x)
{
return *x;
}
int main()
{
my m1(10);
my m2(99);
m1 = f(&m2); // creates a new object
m1 = m2; // does not create a new object
}
Why and where is copy constructor called causing the output CC100 and D100?
In this function
my f(my* x)
{
return *x;
}
called in statement
m1 = f(&m2); // creates a new object
the copy constructor is called to copy object *x in the return temporary object.
In fact it looks as
my tmp = *x; // the copy constructor is called
m1 = tmp;
When trying to think about when a copy constructor is called you should keep a few things in mind:
Scope - functions can't see outside of themselves and their associated namespace. If you want to pass a variable to a function you need to save it in the global environment, repush a scoped copy and then operate on it.
When you use passing by reference you operate on the global copy but since in this case you are returning the value that is pointed to and not a pointer you have to push that return value onto the stack separately because it is stored at a different temporary register address that is popped off the stack after you assign it to a permanent location in main. That's where the destructor comes in.
You made a temporary return value to pass the value out of your function so it's got to be deleted because L1, L2, and L3 cache are all prime real estate.
I highly recommend doing a little bit of reading on assembly code operations or even try compiling simple programs into assembly and seeing how the low level languages work under the hood. Cheers!