Mixing vector objects created on heap and on stack - c++

I have a fairly simple question, but cannot wrap my head over it.
Consider I have this code:
#include <iostream>
#include <vector>
using namespace std;
class B
{
public:
B(const int& val) {this->val = val;}
int val;
};
class A
{
public:
A() {}
void Set(B& ptb)
{
ptBs.push_back(&ptb);
}
void Set(const int& val)
{
ptBs.push_back(new B(val));
}
std::vector<B*> ptBs;
};
int main()
{
A* ptA = new A();
ptA->Set(B(10));
ptA->Set(38);
for (int i=0; i<ptA->ptBs.size(); i++)
cout << ptA->ptBs[i]->val << endl;
delete ptA;
system("pause");
return 0;
}
The output result is:
10
38
But I think there is memory leak is going on in void Set(const int& val) if I won't call delete with array elements, created by this method.
How can I say, which elements of std::vector have been created on heap so I could free memory in ~A() destructor like this:
~A()
{
for (int i=0; i<ptBs.size(); i++)
delete ptBs[i];
}
And do I have to delete vector elements, created via temporary new operation call at all?
Probably I don't see something very simple here, but I really need this functionality in my application.
PS. 10 and 38 are just a simple example. Set function can be called thousands of times with different arguments.

Fortunately, this line won't compile:
ptA->Set(B(10));
This is because B(10) is a constructor cast expression which creates a prvalue temporary of type B; a prvalue cannot bind to the lvalue reference B & parameter to void A::Set(B& ptb). This is the C++ language protecting you from the consequences of storing a dangling pointer to a temporary value.
It usually makes more sense for A to store its B items by value:
std::vector<B> Bs;

You should decide on whether you give ownership of the object of type B to the instance of A or not. Mixing both will not lead to anything good. Just imagine documenting this class: this class may or may not take ownership to the objects it holds.
Alternative approach that I do not recommend is to create a wrapper to pointers to B, that takes a pointer to B and a boolean flag in it constructor and the boolean flag will indicate if the pointer is to an object allocated on the stack or to an object on the heap.

Related

How to Point a base class pointer array to a derived class object on a specific index

How can I point pointer array of class A at index 1 to a derived class object. so when I write pointer[1].print(), it calls the print function from class B. (its index 0 should remain pointing the the object of type A)
#include <iostream>
using namespace std;
class A
{
protected:
string name;
public:
A()
{
name="A";
}
virtual void print()
{
cout<< name;
}
};
class B : public A
{
public:
B()
{
name="B";
}
void print()
{
cout<< name;
}
};
int main()
{
A *pointer=new A [2];
pointer[0].print(); //prints A
//now I want index 1 to be pointed to object of child class B
//so when I write pointer[1].print()
// "B" is printed.
}
A* pointer = new A[2]; reserves space for exactly two As. You simply cannot force a B into this location because (usually) it requires more space.
Polymorphism generally only works via pointers or references:
void demo1(A a); // accept a by value; you *can* pass a B to, but then only its
// A part is copied, anything belonging to B gets lost
// this is called object slicing
void demo2(A& a); // now can accept both A and B without losing any
// type information
void demo3(A* a); // alike...
Same applies for arrays, solely the reference option is not available:
A** array = new A*[2] { new A(); new B(); };
If you allocate via new, don't forget to delete them as well to avoid memory leaks.
You might want to prefer smart pointers to avoid explicit memory management for the created objects; a std::vector of smart pointers relieves you from any memory management entirely (in above example you need to delete[] array manually as well):
std::vector<std::unique_ptr<A>> v;
v.reserve(2);
v.push_back(std::make_unique<A>());
v.push_back(std::make_unique<B>());
Unfortunately, std::initializer_list constructor is not usable as std::unique_ptr is not copiable.
Other ways to initialise the vector are demonstrated here, but these aren't necessarily better either.

What will destructor of a std::variant do if it contains void* data

I have just started using std::variant in my projects. I have a doubt. What will the destructor of std::variant do in the code shown below. Variant holds a void* data. Once variant goes out of scope, I think it will only free the memory of void* but not the actual object the pointer was pointing to. So there will be memory leak in this case. I would like to know if my understanding is correct or not.
#include <iostream>
#include <memory>
#include <variant>
using namespace std;
class A {
public:
~A(){
cout<<"Destructor called"<<endl;
}
};
int main() {
std::variant<void*> data;
A* b = new A();
data = (void*)b;
return 0;
}
When the variant destructor fires, it will call the destructor for whatever type of item is stored in the variant at that point. If that’s a void*, then C++ will say “okay, I will clean up the void*, and since that’s a primitive type, that’s a no-op.” It won’t look at the void*, realize that it’s actually a pointer to an A, and then delete the pointer as though it’s an A*.
The comments have pointed out that it’s fairly unusual to use a variant of a void*. A void* means “I’m pointing at something, and it’s up to you as the user to keep track of what it is and do the appropriate casting and resource management.” A variant means “I’m holding one of the following actual things, and I want C++ to remember which one and to do the appropriate resource management for me.” You may want to rethink your design, as there might be an easier way to do whatever you’re aiming to do here.
You are correct. The only pointer owning classes in the standard library that actually does delete (or delete[]) on pointers are the smart pointers.
std::variant is supposed to support you to hold one object of any number of types and primarily not pointers to objects. If the variant contains pointers, it means that some other object owns the data and is responsible for deleting it.
A std::variant capable of holding only one type is rarely useful either. You can declare the variable as a normal variable of that type in that case.
Here's one example of using a std::variant capable of holding objects of two unrelated types, and destruction will happen as expected.
#include <iostream>
#include <variant>
class A {
public:
~A() { std::cout << "A destructor called\n"; }
};
class B {
public:
B() {}
B(const B&) = default;
B& operator=(const B&) = default;
~B() { std::cout << "B destructor called\n"; }
};
int main() {
std::variant<A, B> data; // now holds a default constructed A
data = B(); // deletes the A and now holds a default constructed B
std::cout << "---\n";
}
Output:
A destructor called // in "data = B()", the A must be destroyed
B destructor called // the temporary B used in "data = B()"
---
B destructor called // the B in the variant when the variant goes out of scope

c++ translate from dynamic allocation to references

I have following code:
class A{
public:
virtual do_something() = 0;
}
class B : public A{
public:
virtual do_something() override;
}
void use_a(A *a){
if (a){
a->do_something();
delete a;
}
}
use_a( new B() );
How this can be translated to references?
Notice do_something() is not const method.
I thought it can be something like this:
void use_a(A &&a){
a->do_something();
}
use_a( B() );
but someone told me this is bad style and must be avoided.
Rvalue references have move sematics. That does not work well when moving B as A.
Use lvalue reference:
void use_a(A &a);
B b;
use_a(b);
or a template:
template <typename T>
void use_a(T &&a);
or, if it doesn't need to be a reference, a smart pointer:
void use_a(std::unique_ptr<A> a);
void use_a(std::shared_ptr<A> a);
Quite simply you convert from a pointer to a reference by providing a concrete instance, i.e. you dereference:
void f(int& i);
f(*(new int)); // do not do this!
The problem is that raw pointers in C++ are precisely that - they do not have automatic lifetime scope, and by converting to an lvalue reference, you have suggested a contract that the instance is concrete and should not be destroyed by the receiver.
int* ptr = new int;
f(ptr);
delete ptr; // otherwise it leaked
Modern C++ uses RAII to provide controlled automatic lifetime management, and C++11 introduced unique_ptr and shared_ptr for handling pointers. With C++14 we also have the mechanisms to avoid raw pointers entirely.
std::unique_ptr<int> ptr = std::make_unique<int>(/* ctor arguments here */);
f(ptr.get());
// now when ptr goes out of scope, deletion happens automatically.
See also http://en.cppreference.com/w/cpp/memory/unique_ptr
Only one std::unique_ptr should have the address of a given allocation at any time (it assumes ownership and will delete the allocation on exiting scope if it's not released).
For a ref-counted pointer: http://en.cppreference.com/w/cpp/memory/shared_ptr
--- EDIT ---
Based on the OPs comments:
Firstly note that
Pair p = { "one", "two" };
// and
Pair p("one", "two");
Pair p{"one", "two"};
are synonymous, in all cases they create a stack-local variable, p, by allocating stack space and calling Pair::Pair("one", "two") to construct a Pair object there.
Remember, however, that this is a stack variable - it has an automatic lifetime and will expire at the end of the current scope.
{ Pair p{"one", "two"}; list_add(list, p); } //p is destroyed
In theory, you can replace this with
list_add(list, Pair{"one", "two"});
But what matters is whether list_add expects you to keep the object around until you remove it from the list... That is often what a list-based function that takes a pointer is expecting. If it takes a non-const reference, it may do the same.
To answer your original post::
struct A { virtual void doSomething() {} };
struct B : public A { virtual void doSomething() override() {} };
void useDoSomethingInterface(A& a) {
a.doSomething();
}
int main() {
A a;
B b;
useDoSomethingInterface(a);
useDoSomethingInterface(b);
}
consider the following:
void list_add(IList& list, Pair& pair) {
pair.next = list.head;
list.head = &pair; // << BAD NEWS
}
void badness(IList& list) {
list_add(list, Pair("hello", "world"));
}
void caller() {
IList list;
badness(list);
// list.head now points to a destroyed variable on the stack
C-pointers in C++ are raw, machine level pointers. They don't ref count. And C++ object instances have a fixed well defined lifetime: till the end of the scope.
However, if list_add is taking its data by value
void list_add(IList& list, Pair pair)
Then we'll be ok. The temporary Pair we create will have to be copied once to create pair and then copied again into the list, which is a shame but at least it won't crash.
your code is a bit unsafe.
first, what if a is null? you didn't check it.
second, what if a points to a stack-object or data-segment-object? you'll have unexpected behaviour (=crash on most of the OS).
if your object has to be dynamically alocated, just use std::shared_ptr
void use_a(std::shared_ptr<A>& a){
a->do_something();
}

Using class pointers vs instance

What I don't understand is what is the difference between using a pointer to a class and generating a new instance of it. It's just for performance? Here I made a class and made m the pointer to the class and n the instance of the class.
And another question: can i make a pointer the class and use another constructor? like myClass* p(7); p->afis(); ?
#include <iostream>
using namespace std;
class myClass
{
int a;
public:
myClass(void);
myClass(int);
void afis();
~myClass(void);
};
myClass::myClass(void)
{
a = 5;
}
myClass::myClass(int nr)
{
a = nr;
}
void myClass::afis()
{
cout << a;
}
myClass::~myClass()
{
}
int main()
{
myClass* m; //<--
m->afis();
myClass n(7); //<--
n.afis();
cin.get();
}
myClass* m;
is just an pointer to the type myClass it does not point to any valid object, dereferecing such a pointer is Undefined Behavior.
An Undefined Behavior means that your program is invalid and it may seem to work or it may crash or it may show any weird behavior, all safe bets are off. So just because your program works does not mean it is safe and it will always work.
To write a valid program you will have to make the pointer point to a valid object.
For example:
myClass obj;
myClass*m = &obj;
In the second case:
myClass n(7);
It creates an object n of the type myClass by calling the constructor of myClass which takes one argument of the type int.
This is a valid way of creating an object.
can i make a pointer the class and use another constructor
Making a pointer doesn't call a constructor. The pointer is uninitialized until you set it to the address of some object (maybe a brand new object created with new).
myClass* m; //<--
m->afis();
This is undefined behavior, you have a wild pointer because m hasn't been initialized.
Better:
std::unique_ptr<myClass> m(new myClass(constructor, args, here));
m->afis();

create an instance for a pointer in other scopes

I have two methods to create an instance for a pointer.
But one of them will fail.
class A {
public:
int num;
};
void testPointer1(A* a){
a = new A();
a->num = 10;
}
A* testPointer2(){
A* a = new A();
a->num = 10;
return a;
}
void testPointer() {
A* a1 = NULL;
testPointer1(a1); // this one fails
//cout << a1->num << endl; // segmentation fault
A* a2 = NULL;
a2 = testPointer2();
cout << a2->num << endl;
}
why is testPointer1 wrong?
The syntax is valid, but it doesn't do what you want because testPointer1() is operating on a copy of the pointer, not the actual pointer itself. So when you assign the address to the newly allocated object, it gets assigned to the copy, not to the original a1 pointer.
Because of this, the address is lost and you get a memory leak. Also, since the original a1 pointer was never modified in the first place, you attempted to dereference a null pointer, which is a bad thing.
I'd say testPointer2() is the better way to do it, but if you want testPointer1() to work, try this:
void testPointer1(A*& a)
{
a = new A();
a->num = 10;
}
The parameter type indicates "a reference to a pointer to A." That way, instead of a copy of the pointer being passed, a reference to the original pointer will be passed. A C++ reference is an alias to another object. So whatever you do on the alias, it gets performed on the original object.
Extra notes:
Note that the parentheses in new A(); are actually significant and their presence or absence makes a difference.
Also note that you must manually delete all new'ed objects after you're done with them, or you will get a leak. Typically you would wrap the pointer in its own class and implement RAII or use a smart pointer such as Boost's smart pointers or auto_ptr, for proper memory management and exception safety.
If you're going to set the value of num on initialization, why not create a constructor?
class A
{
public:
A(int n) : num(n) {}
int GetNum() const { return num; }
private:
int num;
};
void testPointer1(A*& a)
{
a = new A(10);
}
A* testPointer2()
{
return new A(10);
}
// auto_ptr example, see link in second note above
std::auto_ptr<A> testPointer3()
{
return auto_ptr<A>(new A(10));
}
The testPointer1 functions works on a copy of the provided pointer : modifications to a in testPointer1 are not reflected to the caller.
It's exactly like in this simpler example :
void testInt1(int i)
{
i++;
}
void testInt()
{
int i = 0;
testInt1(i);
// i is still 0
}
If you want the change in testInt1 to be reflected to the caller, you have to pass either a pointer or reference to i (and not just the value of i). The same solution can be applied to your specific case, though one could argue that pointers to pointer and references to pointer are not really a best practice.
Is this homework ?
This seems to be obvious:
formal parameters are saved on the stack & restored after method/function call.
then whatever f(type x), manipulating x inside the function/method won't change it's value outside of the function.
even if type is a pointer type.
the only way to make x change inside a function is to tell it is modifiable through references or pointer to type.
in your case :
A* a1 =NULL
call to your method won't change value of a1 outside of testPointer1
so a1 will still be NULL after the call.