I need to register object in global list. I know I can't use make_shared_from_this in constructor - what do I use instead?
vector<shared_ptr<A> > alpha;
struct A : enable_shared_from_this<A>
{
int x;
A():x(9)
{
//alpha.push_back(shared_from_this());
//alpha.push_back(shared_ptr<A>(this));
}
};
1) first push back would result in crash:
ibc++abi.dylib: terminating with uncaught exception of type std::__1::bad_weak_ptr: bad_weak_ptr
2) second push back would result in segmentation fault
You cannot use shared_from_this from constructor and you actually don't need shared_from_this here. You can just write something like create function.
vector<shared_ptr<A> > alpha;
// in struct A
static shared_ptr<A> create()
{
shared_ptr<A> pointer = make_shared<A>();
alpha.push_back(pointer);
return pointer;
}
put constructor in private location and use any trick from How do I call ::std::make_shared on a class with only protected or private constructors?
Is the global vector just meant to list all the objects in memory or do you actually delete objects from the vector. In the later case ForEveR gave a good answer. In the former case, if the code would work, none of the shared_ptr you create would get deleted until the end of the program because they are stored in a global vector. In this case just keep it simple and use old style pointers and add them at the constructor and delete in destructor. For efficiency it's better to change the vector data type. E.g.,
#include<iostream>
#include<memory>
#include<unordered_set>
class A;
std::unordered_set<A*> alpha;
class A{
public:
A(): x(9)
{
alpha.insert(this);
}
~A(){
alpha.erase(this);
}
private:
int x;
};
Example test:
int main(){
std::shared_ptr<A> a= std::make_shared<A>();
std::cout << "Number of objects: " << alpha.size() << std::endl;
{
std::shared_ptr<A> a1= std::make_shared<A>();
std::shared_ptr<A> a2= std::make_shared<A>();
std::cout << "Number of objects: " << alpha.size() << std::endl;
}
std::cout << "Number of objects: " << alpha.size() << std::endl;
}
Number of objects: 1
Number of objects: 3
Number of objects: 1
Related
Class B expects to receive an instance of shared_ptr<IError>.
Class A implements IError and is passed by value to the constructor of B.
I would like to understand how this scenario is handled. How does the shared_ptr as a template class handle the conversion to IError?
In a simple case where B receives shared_ptr<A> I assume the copy constructor is called and the reference counter is increased. However since IError is pure virtual a normal copy constructor invocation seems not to be case here?
// Example program
#include <iostream>
#include <string>
class IError
{
public:
virtual ~IError(){};
virtual void OnError() = 0;
};
class A : public IError
{
public:
A(){};
void OnError(){std::cout << "Error Occured" << std::endl;}
};
class B
{
public:
B(std::shared_ptr<IError> errorReporter): mErrorReporter(errorReporter){}
void Action(){mErrorReporter->OnError();}
private:
std::shared_ptr<IError> mErrorReporter;
};
int main()
{
auto objA = std::make_shared<A>();
auto objB = std::make_shared<B>(objA);
objB->Action();
}
Debugging time! Let's find out what happens by using the tools we have available as developers.
The memory of the shared_ptr objA looks like this (type &objA in the memory window; it will be replaced by its address):
It has a pointer to the object (000002172badd8e0) and a pointer to the control block.
The control block looks like this (copy and paste the second value into a new memory window):
It has a pointer to the allocator (first 2 columns), the reference count (1) and the weak reference count (0 + offset 1).
After objB has been created, the control block of objA has changed to a reference count of 2:
And the shared_ptr objB looks like this:
It points to the a shared pointer and to the control block.
The shared pointer in objB points to the same object as before (000002172badd8e0), so no copy of the actual object has been made.
The control block of objB indicates that objB only has a reference count of 1:
a normal copy constructor invocation seems not to be case here?
Correct. No copy of the object is made, as we can confirm with a debugger. But a copy of the shared_ptr has been made.
It doesn't.
Copy a shared_ptr doesn't copy it's point-to object, just like normal pointer
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<IError> i = a;
A* a = new A;
IError* i = a; // no copy A
You are right in that the base class IError is abstract, hence it cannot be instantiated, never mind copied.
The code below has been modified from the original to show how each newly created shared_ptr just increments the reference count of the original shared_ptr. So, a shallow copy.
In your code, as well as in the code below, the underlying object to these shared_ptrs is concrete class A, derived from the abstract IError, so it is legal to shallow copy it.
// Example program
#include <iostream>
#include <string>
#include <memory>
class IError
{
public:
virtual ~IError(){};
virtual void OnError() = 0;
};
class A : public IError
{
public:
A(){std::cout << "A created.\n";};
void OnError(){std::cout << "Error Occured" << std::endl;}
};
class B
{
public:
B(std::shared_ptr<IError> errorReporter): mErrorReporter(errorReporter){
std::cout << "B created from A.\n";
}
void Action(){mErrorReporter->OnError();}
private:
std::shared_ptr<IError> mErrorReporter;
};
int main()
{
auto objA = std::make_shared<A>();
std::cout << "I. Reference count for objA: " << objA.use_count() << '\n';
auto objB = std::make_shared<B>(objA);
std::cout << "II. Reference count for objA: " << objA.use_count() << '\n';
// objB->Action();
auto objBB = std::make_shared<B>(*objB);
std::cout << "Created objBB from objB\n";
std::cout << "III. Reference count for objA: " << objA.use_count() << '\n';
std::cout << "Reference count for objB: " << objB.use_count() << '\n';
std::cout << "Reference count for objBB: " << objBB.use_count() << '\n';
// auto objB_from_base = std::make_shared<B>(IError()); // ERROR: IError is an abstract class
}
with output:
A created.
I. Reference count for objA: 1
B created from A.
II. Reference count for objA: 2
Created objBB from objB
III. Reference count for objA: 3
Reference count for objB: 1
Reference count for objBB: 1
Changing values of classes/structs inside classes are a mystery to me. I tried to do some research today and came up with the following solution. I wonder if this is a proper way for a function to change stuff inside the class. Is there a need to for this to be somehow done with pointers? Is there a more proper way to accomplish this?
#include <iostream>
int main()
{
class Someclass {
private:
int Integer;
public:
Someclass(int i):
Integer(i){} //CTOR
struct Somestruct {
int a, b;
};
Somestruct Mystruct;
void func(){
Mystruct.a = Integer/2;
Mystruct.b = Integer*2;
};
};
Someclass A(10);
A.func();
std::cout << A.Mystruct.a << " " << A.Mystruct.b << std::endl;
}
The reason I am writing this code, is because I want to parse a file, starting from the line "Integer" into a customly defined struct "Mystruct" which this class should somehow deliver me. Is this an acceptable way to write such a code?
I understand that your question is about encapsulation, being understood that the inner struct is a data holder and the outer class has to manage it somehow.
Weaknesses of your design
In your design, Mystruct is public. So anything outside Someclass could access the data, but also change it. This is error prone, as there is no guarantee that the outside code doesn't break some invariant of the structure.
Ways for improvement
The cleanest thing would certainly to make some getters and setters to access the data. But with 30 members, it's a lot of code.
If your construction process initialises the struture's data, a second approach could be to limit outside access to read-only. You'd do that by making Mystruct private and offering a function returning a const reference:
class Someclass {
Somestruct Mystruct;
public:
...
const Somestruct& get() { return Mystruct; }
};
std::cout << A.get().a << " " << A.get().b << std::endl;
Online demo
Nevertheless before going into that direction, I'd check if access to the structure's raw data couldn't be encapsulated, for example by providing functions that manage the data without need to know the internals:
class Somestruct {
...
public:
ostream& show_simplified_specs(ostream& os) {
os << a << " " << b;
}
}
A third approach could be to use the builder design pattern to encapsulate the construction process of a Someclass based on Somestruct and other parts.
Pointers ?
Pointers should be avoided if possible. For example, suppose you have a vector of Someclass to keep all these classes in memory. At a moment in time, you get a pointer to an element's Mystruct. Suppose you'd then add a new item to the vector: all the previous pointers might get invalidated.
This same risk potentially exist with references. But I think that while it's a common idiom to cache a pointer returned by a function,in practice it's less common and appealing to copy a reference returned by a function.
Is this what you're looking for? I'm not much confident I understood you right.
template <int I>
struct Someclass;
template <>
struct Someclass<1>
{
int Integer = 1;
int a, b;
void func()
{
a = Integer/2;
b = Integer*2;
}
};
template <>
struct Someclass<2>
{
int Integer = 2;
int a, b, c;
void func()
{
a = Integer/2;
b = Integer*2;
c = Integer*Integer;
}
};
int main()
{
Someclass<1> A;
A.func();
std::cout << A.a << " " << A.b << std::endl;
Someclass<2> B;
B.func();
std::cout << B.a << " " << B.b << " " << B.c << std::endl;
return 0;
}
I am having a trouble of putting multiple class objects as member of another class. To be more specific: lets assume we have 2 classes, A and B and class A is nested. I want the main function to have an array with 3 objects of class B. The first object will have 2 objects of class A, the second object will have 5 objects of class A and the third object will have 7 objects of class A. How can i do that? Below is one of my thoughts:
Class A{
private:
int variable;
public:
A(){
cout<< A created! <<endl;
}
~A(){
cout<< A destructed! <<endl;
}
};
Class B{
private:
A array[6]; //It will always create 6 elements of class A...
public:
B(){
cout<< B created! <<endl;
}
~B(){
cout<< B destructed! <<endl;
}
};
int main(){
B* array[3];
for (i = 0 ; i <= 2 ; i++)
{
array[i] = new B(); //Every B element in array have 6 elements of class A
}
}
Thanks in advance!
If you can't use vectors.. (which you should).. here is a working example that shows what you want to do with arrays and manual memory management. https://ideone.com/KihmON
Note: there is no error handling in here. If this was your program it's very unlikely new will ever fail, but for larger objects it can. If you thrown an error in main before your delete statements, those objects will never get deleted. That is why vector is preferred, in the case of errors, it will get cleaned up when it leaves scope no matter what.
#include <iostream>
class A
{
private:
int variable;
public:
A()
{
std::cout << "A created!" << std::endl;
}
~A()
{
std::cout << "A destructed!" << std::endl;
}
};
class B
{
private:
size_t arrayOnHeapSize; // size of array on heap
A* arrayOnHeap; // memory must be allocated before this is used.
public:
B(size_t arrSize) :
arrayOnHeapSize(arrSize)
{
arrayOnHeap = new A[arrSize]; // must deallocate memory manually, use "delete[]" arrays of objects
std::cout<< "B created with size" << arrSize << '!' << std::endl;
}
~B()
{
delete[] arrayOnHeap; // must deallocate memory manually
std::cout << "B destructed! Wouldn't have had to do memory management manually if I had used a vector!" << std::endl;
}
B(const B&) = delete; // If you need to make a copy, you'll have to make a copy constructor that performs a deep copy or adds some (ugly) reference counting logic. Could also opt to implement a move constructor. If you copied this as is, the pointer will get copied, one B will get destructed freeing the memory, then the other B will have a dangling pointer and try to free that upon destruction. No good.
};
int main()
{
B* arrayOfB[3];
arrayOfB[0] = new B(2);
arrayOfB[0] = new B(5);
arrayOfB[0] = new B(7);
delete arrayOfB[0]; // must deallocate manually, using "delete" instead of "delete[]" because these are each 1 object, not arrays.
delete arrayOfB[1];
delete arrayOfB[2];
// Don't need to delete arrayOfB as it is a local on the stack and will be taken care of as the function exits.
}
You can make B a parameterised type (I think that's the correct term):
template<int a>
class B {
A array[a];
};
int main() {
B<2> b1;
B<5> b2;
B<7> b3;
}
However they can't be in an array as B<2> is a different type to B<7> etc.
I am trying to learn C++ and from what I've read in books and on SO:
If I use auto x = new Object(); x is a pointer to address of Object and this is in dynamic memory and exists until I delete it.
However if I use Object x; or auto x = Object() it only lasts until it goes out of scope.
In an example they have shown this:
void foo()
{
Point p = Point(0,0);
} // p is now destroyed.
What I don't understand is what happens when I return a object when I don't use new? Will it be a copy of the object?
Here is an example of what I am not sure about:
class Object
{
public:
int X;
static Object Foo(int y)
{
Object result;
result.X = y;
return result;
}
};
class TestContainer
{
public:
void Run()
{
for(auto i = 0; i < 10; i++)
{
_objects.at(i) = Object::Foo(i + (rand() % 10 + 1));
}
}
private:
std::vector<Object> _objects;
};
void main()
{
TestContainer tc;
while(true)
{
tc.Run();
}
}
Note I haven't tested this code but I think it illiterates my confusion. In my main function I instantiate TestContainer and endless call it's Run method. This in turn loops calling a static Foo method on Object that returns a copy of a new Object, which is stored in a vector.
My question is, what happens with all the Object's? If I replace element 2 in the objects vector with a new Object, is the old value now "out of scope" and is deleted?
Will it be a copy of the object?
Yes.
Or a move could be used instead, or the entire thing could be optimised away to produce only one actual object in your final, compiled program.
But, basically, yes.
If I replace element 2 in the objects vector with a new Object, is the old value now "out of scope" and is deleted?
Yes.
As an aside, you're using at on elements that don't exist; to add elements, use insert or push_back.
A simple class like this behaves much like a POD variable. o1=o2 copies the fields, element-wise. So the target Object of an assignment does not get deleted but overwritten.
Objects which go out of scope "go away" (because the stack is unwound) like e.g. an int.
Here is a run-able example that I believe illustrates this behavior:
#include <iostream>
using namespace std;
class Foo {
private:
int id;
public:
Foo(int x)
: id(x)
{
cout << this->id << " is created" << endl;
}
Foo(const Foo& rhs)
: id(rhs.id)
{
cout << "copied " << this->id << endl;
}
Foo& operator=(Foo rhs){
this->id=rhs.id;
cout << "assigned " << this->id << endl;
return *this;
}
~Foo(){
cout << this->id << " is destroyed" << endl;
}
int getID(){
return this->id;
}
};
Foo bar(){
Foo f1 = Foo(1);
cout << f1.getID() << " from bar" << endl;
return f1;
}
int main(){
Foo f2 = bar();
cout << f2.getID() << " from main" << endl;
return 0;
}
This produces this output:
1 is created
1 from bar
1 from main
1 is destroyed
From this, I'm not seeing a copy or an assignment. I suspect what is happening is that both f1 and f2 are referencing the same instance of the object in memory. The object is not being de-allocated when the f1 reference goes out of scope because the object has another reference assigned to it.
I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).