What is the difference between the 2 following methods to create an object?
Test* t = new Test();
and
Test* t;
Your answers to second sample match with what i thought it would do (no object is created) But
class Test {
public:
void bla(void) {
std::cout << "test" << std::endl;
};
};
int main(void) {
Test* test;
test->bla();
}
gives me the output "test"... So there is actually an Object
The first one does 4 things:
create pointer to Test
allocate memory and creates Test object (note, that it's Test, not test )
the new object is value initialized, because of the () - see Do the parentheses after the type name make a difference with new? for more information
initializes the pointer to point to the created object
The second one just creates pointer to Test. And it's not initialized.
#yogi - for your edit - this is totally Undefined Behavior, as the pointer is uninitialized. And no, it's not an object. See C++ function called without object initialization for more information.
The second one doesn't create any object at all and trying to access it will result in Bad Thingsā¢.
This is a pointer, allocated on the stack, and uses 32 or 64 bits of memory.
Test * t;
This will create an object of type Test on the heap (an you need to desalocate it)
t = new Test();
This will create an object of type Test on the stack (no need to desalocate it. It will disapear as soon as you exit the current context)
Test t2;
Edit
Your example works because the compiler optimized you code : it notices that you don't use any member, so it could doesn't make the effort you look for the instance.
The first one is a method to create an instance of an object.
The second on is not a method to create an instance of an object. It merely declares a pointer, which remains uninitialised.
After your update: The reason that it still successfully calls bla() is just undefined behaviour. Because that's exactly what the C++ Standard defines what is happening when you work with unsafe memory (in this case some arbitrary address that your pointer is pointing to) - the behaviour is undefined.
As others already said, you're just lucky that the undefined behaviour that you trigger happens to look like what you thought you want (essentially because your Test::bla() is almost like a global free function). To see your example crash and burn, just add some non-trivial class members:
class Test {
public:
void bla(void) {
std::cout << "test: " << x << std::endl;
};
int x;
};
You can think of your original example as a free function
void bla(Test * p) { std::cout << "test" << std::endl; }
which you just happen to call with a garbage parameter, but since you don't use the parameter, nothing bad happens. In my modified example, we try to access p->x and die.
Test* test;
test->bla();
As other answers have stated, Test* test does not create any object. It is a uninitialized pointer to Test. It is not pointing to anything valid unless it is initialized to point to a valid Test object.
Dereferencing an Uninitialized pointer like you are results in a Undefined Behaior.
In your case it does not crash because you are not referring this inside bla().
Nevertheless its still undefined behavior to dereference unitialized test.
To reiterate the above point, the following example will mostly crash.
#include<iostream>
class Test
{
public:
int i;
void bla(void)
{
std::cout << "test" << std::endl;
std::cout << "test->i" << this->i <<std::endl;
}
};
int main(void)
{
Test* test;
test->bla();
return 0;
}
Related
I apologise if the title is different from what I will be describing, I don't quite know how to describe it apart from using examples.
Suppose I have a shared_ptr of an object, and within that object, is a vector. I assign that vector to a variable so I can access it later on, and the shared_ptr gets destroyed as it goes out of scope. Question, is the vector I saved "safe" to access?
In the example below, from main(), outer() is called, and within outer(), inner() is called. inner() creates a shared_ptr to an object that contains a std::vector, and assigns it to a variable passed by reference. The role of outer() is to create some form of seperation, so that we know that the shared_ptr is destroyed. In main(), this referenced variable is accessed, but is it safe to use this variable?
#include <iostream>
#include <vector>
#include <memory>
struct sample_compound_obj {
std::vector<int> vektor;
sample_compound_obj(){std::cout << "I'm alive!" << std::endl;};
~sample_compound_obj(){std::cout << "Goodbye, thank you forever!" << std::endl;};
};
bool inner(std::vector<int>& input) {
std::cout << "About to create sample_compound_obj..." << std::endl;
std::shared_ptr<sample_compound_obj> hehe(new sample_compound_obj);
hehe->vektor.push_back(1);
hehe->vektor.push_back(2);
hehe->vektor.push_back(3);
input = hehe->vektor;
std::cout << "About to return from inner()..." << std::endl;
return true;
}
bool outer(std::vector<int>& input) {
std::cout << "About to enter inner()..." << std::endl;
inner(input);
std::cout << "About to return from outer()..." << std::endl;
return true;
}
int main() {
std::cout << "About to enter outer()..." << std::endl;
std::vector<int> vector_to_populate;
outer(vector_to_populate);
for (std::vector<int>::iterator it = vector_to_populate.begin(); it != vector_to_populate.end(); it++) {
std::cout << *it <<std::endl; // <-- is it even "safe" to access this vector
}
}
https://godbolt.org/z/47EWfPGK3
To avoid XY problem, I first thought of this issue when I was writing some ROS code, where a subscriber callback passes by reference the incoming message as a const shared_ptr&, and the message contains a std::vector. In this callback, the std::vector is assigned (via =) to a global/member variable, to be used some time later, after the end of the callback, so presumably the original shared_ptr is destroyed. One big difference is that in my example, I passed the std::vector by reference between the functions, instead of a global variable, but I hope it does not alter the behavior. Question is, is the std::vector I have "saved", suitable to be used?
is it safe to use this variable?
Yes, in the below statement, you copy the whole vector using the std::vector::operator= overload doing copy assignment. The two vectors do not share anything and live their separate lives and can be used independently of each other.
input = hehe->vektor;
In this case it's safe, because you get copy of the vector in this line:
input = hehe->vektor;
One big difference is that in my example, I passed the std::vector by reference between the functions, instead of a global variable, but I hope it does not alter the behavior.
Any reference can be bound only once, and in your scenario input reference is already bound to the argument passed (to be precise std::vector<int>& input of inner function is bound to std::vector<int>& input of outer function which itself is bound to std::vector<int> vector_to_populate). After a reference is bound, it acts as is object itself, so in the assignment statement you actually end up with calling something like this:
input.operator=(hehe->vektor);
Where operator= refers to the std::vector<T>::operator=(const std::vector<T> rhs) function.
If you're familiar with the RAII concept and C++ references, you can pretty much skip the following explanations
In C++, vectors, and as a matter of fact, pretty much all structs, defined in std work very differently from what you might be used to in other higher level languages, like Java or C#. In C++, the RAII (resource acquisition is initialization) technique is used. I highly recommend that you actually read the article, but in short, it means that an object will define a constructor and a destructor, that allocate and free all memory used by the object, in your case, a std::vector, and the language is going to call the destructor when the object falls out of scope. This ensures that there are no memory leaks.
However, how would we go about passing a std::vector to a function, for example? Well, if we just made a straight up copy of the object, byte by byte, as we'd do in C, the function would run fine, until we reach the end of the function, and we call the destructor of the vector. In that case, after the function executes, when we go back to the caller, the vector is no longer valid, because its data got freed by the callee.
void callee(std::vector<int> vec) { }
void caller() {
std::vector<int> vec;
vec.push_back(10);
callee(vec);
vec.push_back(10); // This will break, with our current logic
}
Well, the keyword here is "copy". We copied the vector so that we can pass it in the callee function. We can solve this issue by creating custom copy behavior, in C++ terms that would be a copy constructor. In simple terms, a copy constructor takes an instance of the type itself as an argument, and copies it in the current instance. This allows us now to execute the code from above without any issues.
There are a lot more intricacies to it than I've written here, but other people have said it better than I have. In short, whenever you try to make an assignment, or pass an argument, you utilize the copy constructor (with some exceptions). In your case, you assign a vector variable with a vector value. This vector value gets copied, and so is valid until the function goes out of scope. There is a catch to that thou: if you try to modify the vector, you will modify only the copy, not the original. If you want to do so, you'll need to utilize references.
In C++, we have the concept of references. You can consider the reference something like a pointer, with some caveats to it. First of all, unlike pointers, you can't have a reference to a reference. The reference tells C++ that you don't work with the object itself, but an "alias" of the object. The object will exist in one place in the memory, but you will be able to access it in two places:
int a = 10;
int &ref_a = a;
std::cout << ref_a << ", " << a << "\n"; // 10, 10
ref_a = 5;
std::cout << ref_a << ", " << a << "\n"; // 5, 5
a = 8;
std::cout << ref_a << ", " << a << "\n"; // 8, 8
In the line int &ref_a = a, we don't actually copy a, but we tell ref_a that it is a reference of a. This means that any operations (including assignment) will be applied to a, not to ref_a. We can use references with variables, fields, return values and parameters. A reference is valid as long as the value it refers to is valid, so as soon as the value goes out of scope, the reference is no longer valid.
References can be used in parameters, in order to avoid copying the value. This can provide a lot of performance benefits, since we don't need to copy the value, but just pass a "pointer" to it. Of course, this means that if the function modifies the parameter, that is reflected in the caller:
void func(int &ref) {
ref = 5;
}
void func2() {
int a = 10;
func(a);
std::cout << a; // 5
}
TL; DR
In your case, you're returning a vector via an out parameter (reference parameter). Still, even if you're working with references, setting a reference will actually set the object behind the reference, and will use the copy constructor of the object. You can avoid that by making that a reference of a pointer to a vector, but working with pointers in C++ is strongly advised against. Regardless, the answer to your question is that this code is completely safe. Still, if you try to modify input in outer, you won't modify the vector in hehe, but instead you're going to modify the copy that inener has created.
Disclaimer: I know this is not how unique_ptr should be used, but for the sake of understanding, I would like to know what is going on here. Thank you!
Consider this function:
void foo(int* a) {
unique_ptr<int> pointer_in_function(a);
}
And this main function:
int main(void) {
int* myInt = new int(5);
unique_ptr<int> pointer_in_main(myInt);
foo(myInt);
cout << *pointer_in_main << endl;
cout << *pointer_in_main << endl;
cin.get();
return 0;
}
I consistently get the correct answer from the first cout. The second is undefined. The program sometimes crashes with a critical error on exit, but not always.
What I do not understand is why the first cout gives the correct answer consistently. Shouldn't the integer pointed to by myInt have been deleted when pointer_in_function went out of scope? Thank you for your help!
edit: As an aside, just to be sure, am I correct in my assumption that calling foo should delete my integer because pointer_in_function goes out of scope?
What I do not understand is why the first cout gives the correct answer consistently.
Most implementations do not clear memory after deleting or return it back to the OS, so if you inspect the memory quickly after deleting, the chances of it not having been overwritten yet are higher.
That's one of the valid consequences of undefined behaviour. It may be 100% predictable on your particular implementation, though it need not behave the same on others.
It's not a good way to do (pure enough) experiments with constructors / destructors or deletion. If you have an object uncorrupted it DOESN'T imply that a delete operator hasn't been called (as its effect to the memory data is undefined and indeed many memory manager implementations don't change the released memory content immediately). Instead, create a class with explicit constructor(s) and destructor reporting their invocation and use it in place of int. As a destructor call prepends an object deletion (and as your code doesn't use stack or static allocation of an object under test, a destructor call is always implies a deletion), you may use destructor calls to trace deletions. Something like:
#include <iostream>
class MyObj {
int value;
MyObj(int v) : value(v) {std::cerr << "MyObj ctor called"<<std::endl;}
~MyObj() {std::cerr << "MyObj dtor called"<<std::endl;}
};
.....
int main (int argc, char **argv) {
MyObj* myInt = new MyObj(5);
....
}
I have in my project a couple of functions that create objects. For example, if you have a function that makes an object like this:
int& f()
{
int *i = new int(5);
return *i;
}
and then when you call that you do
int x = f();
or something like
std::cout << f();
what happens to the int that was created in the function? Is the reference handled like a normal variable or am I doing something terribly wrong? And if so, what is the correct way to make objects?
This is terribly wrong, indeed. The moment you forget about your reference is the moment you'll leak a resource. And you're doing just that with int x = f();.
Same with the second case, std::cout << f(); - don't use this at all if you aren't going to delete that dynamically allocated int.
int is also passed to std::basic_ostream::operator<< by value, a copy is made. This doesn't actually matter, no normal code would accept a reference and then call delete &ref;.
Here's a link for you: RAII.
I can't know what you want from your contrived example, but consider returning by value, or using smart pointers in case of polymorphism.
if you want to show that function delegates ownership of the created object with new you have to do it explicitly for example with std::unique_ptr. As you can see your function becomes self documented and you need not look into the body to understand who response for deleting:
std::unique_ptr<int> foo() {
return std::make_unique<int>(5);
}
I'm going through some tutorials on how smart pointers work in C++, but I'm stuck on the first one I tried: the unique pointer. I'm following guidelines from wikipedia, cppreference and cplusplus. I've also looked at this answer already. A unique pointer is supposed to be the only pointer that has ownership over a certain memory cell/block if I understood this correctly. This means that only the unique pointer (should) point to that cell and no other pointer. From wikipedia they use the following code as an example:
std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; //Compile error.
std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is rendered invalid.
p3.reset(); //Deletes the memory.
p1.reset(); //Does nothing.
Until the second line, that worked fine for me when I test it. However, after moving the first unique pointer to a second unique pointer, I find that both pointers have access to the same object. I thought the whole idea was for the first pointer to be rendered useless so to speak? I expected a null pointer or some undetermined result. The code I ran:
class Figure {
public:
Figure() {}
void three() {
cout << "three" << endl;
}
};
class SubFig : public Figure {
public:
void printA() {
cout << "printed a" << endl;
}
};
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t; // used to halt execution so I can verify everything works up til here
testing->three(); // why is this not throwing a runtime error?
}
Here, testing has been moved to testing2, so I'm surprised to find I can still call the method three() on testing.
Also, calling reset() doesn't seem to delete the memory like it said it would. When I modify the main method to become:
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t;
testing.reset(); // normally this should have no effect since the pointer should be invalid, but I added it anyway
testing2.reset();
testing2->three();
}
Here I expect three() not to work for testing2 since the example from wikipedia mentioned the memory should be deleted by resetting. I'm still printing out printed a as if everything is fine. That seems weird to me.
So can anyone explain to me why:
moving from one unique pointer to another unique pointer doesn't make the first one invalid?
resetting does not actually remove the memory? What's actually happening when reset() is called?
Essentially you invoke a member function through a null pointer:
int main()
{
SubFig* testing = nullptr;
testing->three();
}
... which is undefined behavior.
From 20.8.1 Class template unique_ptr (N4296)
4 Additionally, u can, upon request, transfer ownership to another
unique pointer u2. Upon completion of such a transfer, the following
postconditions hold:
u2.p is equal to the pre-transfer u.p,
u.p is equal to nullptr, and
if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
(emphasis mine)
After the std::move() the original pointer testing is set to nullptr.
The likely reason std::unique_ptr doesn't check for null access to throw a runtime error is that it would slow down every time you used the std::unique_ptr. By not having a runtime check the compiler is able to optimize the std::unique_ptr call away entirely, making it just as efficient as using a raw pointer.
The reason you didn't get a crash when calling the nullptr is likely because the function you called doesn't access the (non-existent) object's memory. But it is undefined behavior so anything could happen.
On calling std::unique_ptr<int> p3 = std::move(p1); your original pointer p1 is in undefined state, as such using it will result in undefined behavior. Simply stated, never ever do it.
I use boost shared_ptr to wrap a pointer. However I can only get the correct value in test_shared_ptr(), while in main(), I get the wrong value.
Expected output:
100
100
Actual output:
100
-572662307
It seems that the pointer becomes invalid in that case. Any correct approach to do the job? Thanks in advance.
Below is the source code.
#include <memory>
#include <iostream>
class TestClass
{
public:
TestClass(int &i);
void print_i();
private:
int *_i;
};
TestClass::TestClass(int &i) : _i(&i)
{
}
void TestClass::print_i()
{
std::cout << *_i << std::endl;
}
void print_i(int &i)
{
std::cout << i << std::endl;
}
TestClass *test_shared_ptr()
{
std::tr1::shared_ptr<int> i(new int());
*i = 100;
print_i(*i);
return new TestClass(*i);
}
int main(int argc, char** argv)
{
TestClass *p = test_shared_ptr();
p->print_i();
return 0;
}
You need to pass around the shared pointer, rather than references and pointers directly to the int.
What's happening is the shared pointer is never passed anywhere outside the test_shared_ptr() function. When that function returns, the shared pointer is destroyed. When it sees that nothing else has a reference to it's memory, it destroys the memory it was pointing at.
Basically, where you are using int &i and int *i change both to use std::tr1::shared_ptr<int> i.
You probably need to read up on shared pointer a bit more. Basically, they keep a reference count for the pointer they are pointing to. When they are copied, they up the reference count, and when they are destroyed the decrement it. When the reference count reaches 0 (nothing else is referencing the memory it is pointing at) it frees that memory. So, even though something is using that pointer in your case, because it did not use a shared pointer there is no way for the shared pointer to know that the memory is still being used, so it frees it.
It seems that the pointer becomes invalid in that case
Of course it becomes invalid. shared_ptr gets deleted when you leave test_shared_ptr, and i does not exist after that.
Any correct approach to do the job?
1) simply copy value of i. (use int i instead of int* i in TestClass). int is small, you won't lose anything.
or
2) use std::tr1::shared_ptr<int> instead of int* in TestClass.
The issue you are having is with your API contract.
I don't want to use shared pointer to pass variable values in TestClass's constructor, since I don't want to force the api user to use smart pointer
Your TestClass contract is currently looking like you want the caller to maintain the int item so that it has a lifetime longer than TestClass.
Your test case doesn't follow this contract rule however.
Actually I want to pass object by reference instead of generic type in my application.
Passing by reference or by pointer does not have anything to do with 'generic' type.
Here is a possible fix for your code testing your API, the scope of your int is then longer then sufficiently long (untill the end of the app) to handle all usages within TestClass
TestClass *test_shared_ptr(int &i)
{
i = 100;
print_i(i);
return new TestClass(i);
}
int main(int argc, char** argv)
{
std::tr1::shared_ptr<int> i(new int());
TestClass *p = test_shared_ptr(*i);
p->print_i();
return 0;
}
What you are doing really breaks the point of shared_ptr. Basically when you pass it out of that function is it magically supposed to break and, thus, not free the pointed too memory?
No. It frees it. Are you expecting the shared_ptr to still exist outside of the function so that when "p" drops out of scope it manages to call teh shared_ptr destructor? This can't happen. p is a pointer not a shared_ptr class.
Either return a shared_ptr or return the new'd pointer and delete it yourself.