I am learning pointers in c++ and am having some trouble.
I have a class Foo that in the header file declares some data:
private:
const Bar *obj;
Where Bar is a class.
Then in the c++ implementation I want to replace *obj so that it points to a completely different Bar object. *obj is constant, so how do I change what is in what *obj points to or rather, what is in memory at *obj? Also in Foo's destructor, how do I deallocate *obj?
Given your class definition
class A {
private:
const Bar *obj;
};
obj is a pointer to a constant Bar object. You can change what that pointer points to, but you cannot change the contents of the object pointed to.
So, if you have a new Bar object and you'd like to change obj so it points to that, you can simply assign the new value:
/* New object: */
Bar *new_bar = new Bar;
/* Change the pointer: */
obj = new_bar;
There are two issues, however.
If the new Bar object is created outside the class, you cannot directly assign it to obj because the latter is private. Hence you need a setter function:
class A {
private:
const Bar *obj;
public:
void set_obj(const Bar *new_obj) { obj = new_obj; }
};
You must determine who will eventually own the Bar object, i.e. who is responsible for freeing the heap space it takes. If the caller is responsible then you can code it as above, i.e. class A will never create new Bar objects, nor delete any. It will just maintain a pointer to Bar objects created and deleted outside the class.
But if class A above is actually responsible for the memory space taken by the Bar objects, you must use delete obj in the destructor to free the space, and you must also free the space when you get a new Bar object assigned. That is, the set_obj function above needs to be changed to this:
void set_obj(const Bar *new_obj) { delete obj; obj = new_obj; }
Otherwise you'll have a memory leak. Similar measures must be taken in the copy constructor (unless you delete it), as well as the assignment operator: Both functions are used whenever a copy of a class A object is made, and in that case you must make sure that you do not simply copy the pointer, but instead allocate fresh space and copy the object (i.e. you must perform a deep copy):
A(const A& a):obj(new Bar(*a.obj)) {}
A& operator=(const A& a) { delete obj; obj = new Bar(*a.obj); return *this; }
Having said this, if your class is responsible for the memory space, it is a much better idea to use a smart pointer class instead of a raw pointer. The main reasons are: (i) The above is quite complicated and it's easy to make mistakes; (ii) The above is still not very good – there may still be memory leaks or worse problems when an exception is thrown, e.g. in the constructor of Bar. C++11 provides a smart pointer class called std::unique_ptr, which seems ideal for your purposes:
class A {
private:
std::unique_ptr<const Bar> obj;
public:
~A() {}
void set_obj(std::unique_ptr<const Bar> new_obj) { obj = new_obj; }
};
With this in place, the smart pointer will take care of any memory space that needs to be freed automatically, both at destruction time as well as when a new Bar object is assigned to the pointer.
You cannot use that pointer to to change the value that's being pointed to, that's why it's a const, but you should be able to change what it is pointing to.
On c++ "const Bar *obj;" means that you have a pointer to a readonly Bar object; meaning that you can point it to any readonly Bar object.
You can also point a non constant variable, thus promising that you will not change it using that pointer.
If you want to have a pointer, that is constant in the sense that it can't be made to point anything else, then you should write it this way:
Bar * const obj = some_object;
This will compile and work fine:
const int p = 1, q = 2;
int r = 3;
const int* i = &p;
i = &q; // point it to a different const variable.
i = &r; // point it to a different non const variable.
As written I believe that this is a pointer to a const Bar object and not a constant pointer.
Related
A pointer to a const object doesn't allow to change the object. For example:
class foo {
public:
int m_data;
foo() : m_data{11} {}
};
void change(const foo *obj)
{
obj -> m_data = 21; // gives error, normal
}
This is fine and normal behavior.
What I don't understand is that when we add an additional pointer variable, either of the same type (like foo *) or of some other type (like bar *), but not the basic types like int *, then we can change the value that the pointer points to (from a pointer to the const type itself).
How is this possible?
class foo {
public:
int m_data;
foo *m_next;
foo() : m_data{11}, m_next{nullptr} {}
};
void change(const foo *obj)
{
obj -> m_next -> m_data = 21; // does not give any error! why?
}
This also happens if we take some other type inside foo, like bar *.
Why is this happening? How can I define the function so that I can be sure that my function can't change the value the object is pointing to?
obj -> m_next -> m_data = 21; // does not give any error! why?
Because this is not changing the object. This object's m_next pointer is exactly the same as it was before.
This is only changing whatever m_next is pointing to. Which has nothing to do, whatsoever, with the object that owns this m_next pointer.
Now, if, on the other hand, you try to assign something to the m_next pointer itself, instead of whatever it's pointing to, then you'll get the error you were expecting.
The only thing that the object contains are its enumerated members. None of them are changed by this line of code.
In your example, foo* m_next is a pointer member variable to a mutable foo object. The pointer itself is considered part of the object instance, not the object being pointed to.
By changing m_next, you are changing the pointer, which is considered part of the instance of foo. Doing something like obj->m_next = nullptr; in change would be invalid because you are changing the memory that is part of the constant foo instance. (Note: don't don't set random pointers to null in real code, unless you're sure it's safe, or it's a possible memory leak).
By accessing the object being pointed to by m_next via m_next->, you are accessing memory of another object that is not part of the const instance passed to change. This is perfectly valid.
You could say that constness is not transitive; a const object doesn't make objects accessed through it (via pointers) const.
I have a function that returns an object via a pointer argument. However the object has a private default constructor, so how can I create a variable to pass the address in?
class Foo {
Foo(/*some parameters*/);
private:
Foo();
};
void bar( Foo* foo ) {
*foo = Foo(/*some arguments*/);
}
Foo f; //doesn't compile because default constructor is private
bar( &f );
The code is simplified, I can't really change Foo or bar
Simply use the public, non-default constructor to create the first version of the Foo instance, that will be re-assigned in bar:
Foo f(/*some arguments*/);
bar(&f);
It probably won't matter which argument values you pass, unless the move assignment operator does something special with the old values.
Yes, it seems pointless, but Foo has been designed so that bar is really inconvenient to use (or the other way round).
So there is no way to say just create some space in memory that will fit a Foo, I'll fill it in later?
Not using bar. bar does an assignment, and an assignment requires the left hand side to be an existing object, that is in a valid state.
So why isn't it possible in C++ to create a variable without creating an object?
Why is it in C++ variable and object are so tightly related?
Because that is the way C++ has been specified. A variable is a name for an object. It is not a name for something that might be an object or might be not-an-object. And it's a good decision too. Thanks to this design, you can always rest assured, that the object named by a variable does always exist sans a bug in your program. (Reference variables are different, since they aren't an object themselves).
The issue with Foo and bar isn't a limitation of the language. The issue is bad design of Foo and/or bar.
This doesn't answer the question, because it relies on changing bar, but to answer this comment:
So there is no way to say just create some space in memory that will fit a Foo, I'll fill it in later?
For objects of non-trivial types (like the Foo in your example) the only way to do that is construct a new object at that address, not assign to an existing object. You can do that with a placement new-expression:
void bar( Foo* foo ) {
new (foo) Foo(/*some arguments*/);
}
Now instead of the address of an existing object, the argument to the function needs to be a chunk of uninitialized memory which is suitably-aligned for a Foo object, which you can do with the aligned_storage type:
std::aligned_storage<sizeof(Foo), alignof(Foo)>::type storage;
Foo* addr = reinterpret_cast<Foo*>(&storage);
bar( addr );
However, because you've manually started the lifetime of a Foo at that location, it's also your responsibility to manually end its lifetime, by explicitly invoking the destructor when you're finished with it:
addr->~Foo();
This is obviously more error-prone than relying on the compiler to construct and destroy your object automatically.
I think the person who had written the code for class Foo did not want anyone to create objects of class Foo using default c'tor. Instead he/she wanted to create the objects of class Foo using method bar();
So try this:
class Foo {
Foo(/*some parameters*/);
private:
Foo();
};
void bar( Foo** foo ) {
//*foo = Foo(/*some arguments*/);
*foo = new Foo(/*some arguments*/);
}
Foo *f = NULL; //doesn't compile because default constructor is private
bar( &f );
Note: You need to create a pointer to class Foo i.e *f and pass the address of this pointer. Inside method bar() an object of class Foo will get created and this object's address will be assigned to the pointer f.
I've got a background in C and am trying to get my head around C++ classes and how the destructors get called as objects leave scope. As a side note, given the nature of what I am trying to do, I would rather not use STL structures like std::array<> or std::vector<> for the data containers I present below.
Here's a high level overview of my understanding. Given some class:
class some_class{
public:
int * member;
size_t n_members;
some_class(size_t count) ...
~some_class() ...
// a member function or operator overload
// that returns an instance of some_class
some_class do_something()
}
...
some_class * container;
// Some scope
{
some_class foo = some_class();
some_class * bar = new some_class();
container[0] = bar;
}
When some_class foo leaves the scope, its destructor gets called. If I wanted to store a pointer to an instance of some_class into container outside of the scope, I need to instantiate some_class bar on the heap so that memory does not immediately get de-allocated upon leaving scope - just like I would in C.
Now, the purpose of some_class is to hold an arbitrarily large amount of data and so int * member needs to be allocated on the heap.
Given above, the constructor and destructor for some_class() will look something like this:
// some_class constructor
some_class::some_class(size_t count) : n_members(count){
member = new int[count];
}
// some_class destructor
some_class::~some_class(){
delete[] member;
}
Now my problem becomes apparent: If I need to add an instance of some_class returned from the do_something() method, I am guaranteed to have a memory error (in this case, a double-free) because do_something() returns a stack-allocated some_class:
some_class * container = new some_class[n];
// Some scope
{
some_class foo = some_class();
some_class bar = foo.do_something();
container[0] = &bar; // <-- I know this is stupid but that's the point of this question
}
delete[] container;
My way around this is to make foo.do_something() return a pointer to an instance of some_class. Of course, not a solution. How would one properly address such a situation in true C++ way?
For example, one thing I've been reading up on was the use of shared pointers or unique pointers (or smart pointers in general). However, my understanding is that using these pointers requires you to have instantiated your object in the heap. It also really doesn't help the whole issue about requiring foo.do_something() to return a pointer.
Anyways, any thoughts would be appreciated.
Smart pointer can be used to hold pointer inside some_class like this:
#include <memory>
class some_class{
public:
// smart pointer instead of raw pointer
std::unique_ptr<int[]> member;
size_t n_members;
some_class(size_t count = 0) : member(new int[count]), n_members(count) {}
// destructor not needed
// a member function or operator overload
// that returns an instance of some_class
some_class do_something();
};
int main()
{
int n = 3;
// smart pointer instead of raw pointer
std::unique_ptr<some_class[]> container(new some_class[n]);
{
some_class foo = some_class(10);
some_class bar = foo.do_something();
// use std::move to transfer pointer ownership
container[0] = std::move(bar);
}
// no need to delete
}
I used to be proficient in C++, but moved to Java long ago and my C++ is rusty now :(.
One thing you can do is create a constructor that accepts a member of the class. Inside it, just copy the properties to your new instance. (Also it is possible to make it with a static method instead of overloading the constructor).
some_class::some_class(some_class* obj){
member = obj->member;
n_members = obj->n_members;
}
So you can do this in your code:
some_class * container;
// Some scope
{
some_class foo = some_class();
some_class * bar = new some_class();
container = new some_class(bar);
}
Hope it works for you.
I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.
In writing a copy constructor for a class that holds a pointer to dynamically allocated memory, I have a question.
How can I specify that I want the value of the pointer of the copied from object to be copied to the pointer of the copied to object. Obviously something like this doesn't work...
*foo = *bar.foo;
because, the bar object is being deleted (the purpose of copying the object in the first place), and this just has the copied to object's foo point to the same place.
What is the solution here? How can I take the value of the dynamically allocated memory, and copy it to a different address?
You allocate new object
class Foo
{
Foo(const Foo& other)
{
// deep copy
p = new int(*other.p);
// shallow copy (they both point to same object)
p = other.p;
}
private:
int* p;
};
I do not see the context, but the code you posted doesn't seem like copying the pointer, it is exactly what you ask for — copying whatever it points to. Provided that foo points to the allocated object.
I assume your class looks like this.
class Bar {
Foo* foo;
...
}
In order to do a deep copy, you need to create a copy of the object referenced by 'bar.foo'. In C++ you do this just by using the new operator to invoke class Foo's copy constructor:
Bar(const Bar & bar)
{
this.foo = new Foo(*(bar.foo));
}
Note: this solution delegates the decision of whether the copy constructor new Foo(constFoo &) also does a 'deep copy' to the implementation of the Foo class... for simplicity we assume it does the 'right thing'!
[Note... the question as written is very confusing - it asks for the 'value of the pointer of the copied from object' that doesn't sound like a deep copy to me: that sounds like a shallow copy, i.e. this.
Bar(const Bar & bar)
{
this.foo = bar.foo;
}
I assume this is just innocent confusion on the part of the asker, and a deep copy is what is wanted.]