Trying to understand the example for weak_ptr in Stroustrup's TCPL (pp 995, 4th Ed.). I understand the goal is to grab into a shared pointer (to a neighbor asteroid) when needed. The example code is:
void owner()
{
//...
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i) {
va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]))); // why?
}
}
A lot of stuff is going on in the marked line. I don't understand why reset is used, and why the constructor accepts a weak_ptr? Can someone explain that line in more details?
Interpreting the earmarked line,- Asteroid() constructor will accept a weak_ptr as a parameter and returns a shared_ptr. vector element va[i] relinquished any earlier ownership by calling reset before accepting the new shared_ptr.
The simplified code will look like so: Every new Asteroid will have a pointer to another neighbouring Asteroid, this pointer should be a weak_ptr to avoid cyclic reference due to interconnecting Asteroid pointers.
vector<shared_ptr<Asteroid>> va(100);
for (int i = 0; i < va.size(); ++i)
{
shared_ptr<Asteroid>sp = va[neighbor];
weak_ptr<Asteroid> wp = sp;
shared_ptr<Asteroid>sp2 = make_shared<Asteroid>(wp);
va[i].reset(sp2);
}
The reset fuction is equivalent to the assign operator (=), the difference is that the assign operator adds the shared_ptr object as a shared owner of the Asteroid object's assets, increasing their use_count, while the reset() function makes the shared_ptr acquires ownership of p with a use count of 1, making all the other owners release their ownership.
So, in this code, reset is being used to make va[i] the unique owner of the object at the time.
Related
For better performance in memory management (new resp. malloc takes very much time in my application) I want to reuse objects wrapped by shared_ptr.
I know that the objects have to be deleted as soon as use_count() reaches a certain value. Currently when use_count() equals that value I remove the objects from their containers that they are deleted and create new objects when needed.
Is there a way to get an event (function, lambda expression, whatever) as soon as use_count() reaches a certain value?
If there would be a way, I could write the objects in a list to be reused instead of deletion.
edit: My idea is as follows - written down quickly.
class MyClass {
public:
MyClass() {};
virtual ~MyClass() {}
atomic<shared_ptr<MyClass>> next;
};
// allocate memory quickly in one block
vector<shared_ptr<MyClass>> memory;
memory.reserve(SIZE);
for(unsigned int i = 0; i < SIZE; ++i) memory.emplace_back(make_shared<MyClass>());
atomic<shared_ptr<MyClass>> pool = memory[0];
for(unsigned int i = 0; i < SIZE - 1; ++i) memory[i]->next = memory[i+1];
// object "creation"
shared_ptr<MyClass> create() {
// here everything should be atomically done
shared_ptr<MyClass> c = pool;
pool = c->next;
return c;
}
// object ready for reuse
void deletion_if_use_count_is_1(shared_ptr<MyClass> d) {
// here everything should be atomically done
d->next = pool;
pool = d;
}
Perhaps there's a better way to achieve this?
But as you can see, use_count() will never be 0, but I want to reuse the objects; the shared_ptr don't need to be touched.
You can use a custom deleter for your shared_ptr that actually does not delete the underlying object but inserts its pointer into a list of reusable objects.
You can't specify deleters with make_shared so you will have to write your own, eg:
std::shared_ptr<ExpensiveType> make_shared_ExpensiveType(ExpensiveType* expensiveType)
{
return std::shared_ptr<ExpensiveType>(expensiveType, deleterFunc);
}
You are partially replacing old code from the past. I'm replacing an existing pointer with a smart pointer for this operation, and I'm curious about deallocation. I replaced the code as below, will a leak occur?
std::vector<std::shared_ptr<Interface>> interface_list;
for (int i = 0 ; i < 5; ++i) {
Interface *buffer = CreateFactory(i);
if (buffer) interface_list.emplace_back(buffer);
}
...
for (std::shared_ptr<Interface> it: interface_list) {
it.reset();
}
//IS iT ok?
Assuming you fix the loop to call reset on the actual shared_ptrs instead of copies, the answer is "yes":
for (auto& it: interface_list) {
it.reset();
}
That leaves you with a list of dummy shared_ptr instances, of course.
You can also just clear the vector and have C++ reset the pointers for you:
interface_list.clear();
or just let interface_list go out of scope.
I have a class that acts as a node in a binary tree, one of the methods which I would like to call from inside that class is recursive, and needs to pass itself to the next node in the tree so that the next node knows its own parent. I dont want to store a class member parent because I would like to avoid using a shared_ptr.
The code looks something like this:
void MyClass::expand(MyClass* parent){
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(this);
}
return;
}
But I would like to pass a unique_ptr instead of a raw pointer. However, the pointer to 'this' is already wrapped elsewhere by a unique_ptr already, so I dont want to instantiate another. Is it possible to do this?
If there are any design patterns I should be aware of please let me know.
Any help appreciated
Don't use a pointer at all. You are not taking ownership, the argument is not optional, so use a reference:
void MyClass::expand(MyClass& parent){
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(*this);
}
return;
}
All of your code will perform the same, and it is safer etc.
If you ever have a situation where you want to pass a non-owning pointer that is guaranteed to be non-null (which appears to be the case here), then you probably want to just use a reference instead.
In your case, depending on what doSomethingWithParent performs, you'd probably actually want a const reference as well:
void MyClass::doSomethingWithParent(const MyClass& parent) {
// who knows?
}
void MyClass::expand(const MyClass& parent) {
for (int i = 0; i < children.size; i ++){
children[i]->doSomethingWithParent(parent);
children[i]->expand(*this);
}
}
So, I have an array of a class called "Customer"
Customer** customersarray[] = new Customer*[customer];
I'm receiving int customer with cin.
anyways, in customer.cpp, there is a method called void deactivate().
which goes like this:
void Custmoer::deactivate()
{
if (this != NULL)
remove this;
//this = NULL; I want to do this but it doesn't work.
}
and the purpose of this is to remove it from customer array when satisfies a certain condition. So for example,
for (int i = customer - 1; i >= 0; i--)
{
if (customersarray[i]->getAngerLevel() == 5) {
customersarray[i]->deactivate();
}
for (int z = i; i < customer - 1; i++) {
*(customersarray + z) = *(customersarray + z + 1);
}
customer--;
}
so my first questions are:
why does this = NULL not work?
is there a simpler way to remove something from pointer array when a condition is satisfied? (for example, remove all customers that has anger level of 5.)
Your mistake is thinking that you can remove something from a Customer* array by some magic inside the Customer class, but that's not true. Just remove a customer from the customer array where ever the customer array is. For instance using remove_if
#include <algorithm>
Customer** customersarray = new Customer*[customer];
...
customer = std::remove_if(customersarray, customersarray + customer,
[](Customer* c) { return c->anger() == 5; }) - customersarray;
This updates the customer variable to be the new size of the array, but doesn't free or reallocate any memory. Since you are using dynamic arrays and pointers you are responsible for that.
Which is why you should really not be using pointers or arrays, but using vectors instead.
std::vector<Customer> customerVector;
Life will be so much simpler.
Type of "this" is a constant pointer which means you cant change where it points
Your function can return a boolean and if its true just set your pointer to null
You'll be much better off using a std::vector, all memory memory management gets much safer. You cannot modify the this pointer, but that would be meaningless anyway:
It is a local variable, so any other pointer outside would not be changed, not even the one you called the function on (x->f(): the value of x is copied into this).
It contains the address of the current object - the current object is at a specific memory location and cannot be moved away from (not to be mixed up with 'moving' in the context of move semantics!).
You can, however, delete the current object (but I don't say you should!!!):
class Customer
{
static std::vector<Customer*> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
delete this;
}
}
Might look strange, but is legal. But it is dangerous as well. You need to be absolutely sure that you do not use the this pointer or any other poiner to the current object any more afterwards (accessing non-static members, calling non-static functions, etc), it would be undefined behaviour!
x->commitSuicide();
x->someFunction(); // invalid, undefined behaviour!!! (x is not alive any more)
Similar scenario:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
{
customers.erase(i); // even now, this is deleted!!! (smart pointer!)
this->someFunction(); // UNDEFINED BEHAVIOUR!
}
}
}
If handling it correctly, it works, sure. Your scenario might allow a much safer pattern, though:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
Customer()
{
customers->push_back(this);
};
~Customer()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
}
}
There are numerous variations possible (some including smart pointers); which one is most appropriate depends on the use case, though...
First of all, attending to RAII idiom, you are trying to delete an object before using its destructor ~Customer(). You should try to improve the design of your Customer class through a smart use of constructor and destructor:
Customer() {// initialize resources}
~Customer() {// 'delete' resources previously created with 'new'}
void deactivate() {// other internal operations to be done before removing a customer}
Then, your constructor Customer() would initialize your internal class members and the destructor ~Customer() would release them if necessary, avoiding memory leaks.
The other question is, why do you not use another type of Standard Container as std::list<Customer>? It supports constant time removal of elements at any position:
std::list<Customer> customers
...
customers.remove_if([](Customer foo) { return foo.getAngerLevel() == 5; });
If you only expect to erase Customer instances once during the lifetime of the program the idea of using a std::vector<Customer> is also correct.
I'm an expert level Java programmer, trying to port my knowledge over to C++. This is not homework, just a concept that I'm trying to learn the C++ equivalent of.
What I'm trying to do, is "generate" a list of objects of a custom type using a loop. This is how I would do it in Java:
public class TestClass
{
private ArrayList<ExampleClass> _exampleObjects;
private int _numObjects = 10;
public void populateList()
{
_exampleObjects = new ArrayList<ExampleClass>();
for(int i = 0; i < _numObjects; i++)
{
_exampleObjects.add(new ExampleClass());
}
}
public void doStuffWithListItems()
{
for(ExampleClass e : _exampleObjects)
{
e.performAction();
}
}
}
Super simple stuff. Create a list, iterate through an arbitrary loop and add objects to it. Then, loop through those objects and use them for whatever purpose.
TestClass.h:
class TestClass
{
public:
// Constructor, copy constructor, destructor definitions
void populateList();
void doStuffWithListItems();
private:
std::vector<ExampleClass> _exampleObjects;
const int _numObjects = 10;
};
TestClass.cpp:
void TestClass::populateList()
{
for(int i = 0; i < _numObjects; i++)
{
ExampleObject obj;
_exampleObjects.push_back(obj);
/* What actually goes here in place of obj? */
}
}
void TestClass::doStuffWithListItems()
{
for(auto it = _exampleObjects.begin(); it != _exampleObjects.end(); it++)
{
/* What do i do with my iterator to access my object? */
}
}
Its my understanding that where I initialise my objects in the first loop, they go out of scope and die by the end of each loop iteration. Is that right? If so, how do I make a persistent instance?
I experimented with the shared_ptr<> from and was apparently able to store them persistently, but couldn't for the life of me work out how to dereference from an iterator of a shared_ptr<>.
I feel like this should be a really simple concept. I just can't seem to work it out. I've read a lot on C++ scope and loops. I just can't seem to find anything on both.
ExampleObject obj;
_exampleObjects.push_back(obj);
/* What actually goes here in place of obj? */
Nothing. What you have is correct, assuming ExampleClass has a working copy constructor. If your compiler supports C++11 (and since you're using auto, it at least partially does), you can save yourself a copy.
_exampleObjects.emplace_back();
This constructs an object in place in the vector, forwarding the arguments (none in this case) to a matching constructor (the default ctor, in this case). For accessing the object from the iterator, do this:
for(auto it = _exampleObjects.begin(); it != _exampleObjects.end(); it++)
{
it->performAction();
}
Again, C++11 can make things better here.
for(auto & obj : _exampleObjects)
{
obj.performAction();
}
Its my understanding that where I initialise my objects in the first
loop, they go out of scope and die by the end of each loop iteration.
Correct.
If so, how do I make a persistent instance?
vector<>::push_back takes care of this. It copies the parameter into the vector. In other words, it's not the same object that was created in the loop, it's a copy. You just need to ensure that ExampleClass has non-broken copy semantics.
couldn't for the life of me work out how to dereference from an
iterator of a shared_ptr<>
If you had an iterator into a vector of shared pointers, (call it it), you would dereference it, and call the member function of the stored object, like this:
(*it)->performAction();
// alternatively
(**it).performAction();
The ideal answer suggests a very bad idea - use post increment ++ on iterator in loop.
You should never ever use it in loops where you only need to iterate because postincrement must return the value the iterator had before it was incrementing; so, that previous value needs to be copied somewhere before.
It is just not good from performance perspective and a bad codestyle sign.