I'm relatively new to programming and recently, while I was doing the assignment I came across a problem that I'm not sure how to cope with. I have an abstract class called IPrintable
and it represents printable objects. Class UnorderedSet
is an unordered set of IPrintable
objects, it is actually a dynamically allocated array of pointers to the IPrintable
objects. The problem is that this implementation bounds lifetime of objects that exist somewhere in memory and "elements" in my set. I'm aware that when those objects get destructed my pointers will point to the deallocated memory block. Can someone tell me how to manage it? The only idea that I can think of is to use a dynamically allocated array of shared smart pointers, but I'm not sure how to do that. Maybe something like this?
std::shared_ptr<std::shared_ptr<ns1::IPrintable>> set
; But how to get shared_ptr from the array? Can I use set[index]
?
class UnorderedSet:virtual public IPrintable
{
int* n;
int* i;
IPrintable** set;
public:
UnorderedSet(int n):n(new int(n)),i(new int(0)),set(new IPrintable*[n])
{
for (int j = 0; j < n; j++)
set[j] = nullptr; // I cant have set[j]= new IPrintable
because its abstract class
}
...
void insert(IPrintable* const iprt)
{
if (*i == *n)
this->add_capacity();// extends capacity
set[*i] = iprt;
(*i)++;
}
...
}
class IComparable:public IPrintable
{
virtual double compare_criteria()const = 0;
public:
virtual ~IComparable()=default;
std::strong_ordering operator<=>(const IComparable&)const;
};
class Complex: public IComparable
{
double *re, *im;
public:
...}
int main()
{
Complex* z=new Complex(1,1);
UnorderedSet uset(4);
uset.insert(z);
z->~Complex();// uset.set[0] points to the deallocated memory block
return 0;
}
You can create a container that holds a smartpointer type just like you would with any other type eg:
std::vector<std::shared_ptr<IPrintable>> myvec;
And then you would be able to access it by array indexing:
myvec[0];
A shared_ptr
uses reference counting to know when it should be deleted as the deleter will be called when it reaches 0
references.
A unique_ptr
is used to represent an item which you want only 1
reference to.
You have to take certain care with unique_ptr
in containers as a unique_ptr
is non-copyable.
Eg you could create the pointer within the vector:
std::vector<std::unique_ptr<IPrintable>> myvec;
myvec.emplace_back(std::make_unique<IPrintable>());
And ensure you access the elements by reference rather than taking a copy eg:
for(auto& printable : myvec) {
//use printable unique_ptr
}
Also:
z->~Complex();// uset.set[0] points to the deallocated memory block
You shouldn't be manually calling the destructor but rather call delete
on z
. If you want your UnorderedSet
to take ownership of the allocated memory, you can have your UnorderedSet
call delete
on it's items in the UnorderedSet
's destructor or when an item is removed from the set.
If you are willing to not insist on an unordered set of IPrintable
then the example below might give some guidance. The z
element lives only for a short period and is automatically destroy but still detected by the std::weak_ptr
when iterating over the container.
I deliberately avoid using std::make_shared
in this example since a control block created by std::make_shared
will also hold the allocation area for the object in question. If the weak_ptr
lives a lot longer than the original shared_ptr
then that memory will not be reclaimed until the last weak_ptr
is destroyed.
#include <iostream>
#include <memory>
#include <vector>
class IPrintable
{
public:
virtual ~IPrintable() = default;
virtual void print() = 0;
};
class Real : public IPrintable
{
int re{};
public:
Real(int) {}
void print() override { std::cout << "Real::print()\n"; }
};
class Complex : public IPrintable
{
double *re{}, *im{};
public:
Complex(double, double = double{}) {}
void print() override { std::cout << "Complex::print()\n"; }
};
int main()
{
std::vector<std::weak_ptr<IPrintable>> printables;
std::shared_ptr<Real> r(new Real(3));
{
std::shared_ptr<Complex> z(new Complex(4, 5));
printables.push_back(z);
}
printables.push_back(r);
for(auto& wp : printables)
if(auto sp = wp.lock())
sp->print();
else
std::cout << "Lost entry\n";
}
This example should print:
Lost entry
Real::print()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.