When I try to add an Object pointer to a std::list pointer I get a segfault. Why?
object.h
#ifndef DELETEME_H
#define DELETEME_H
class Object
{
public:
Object(): yes(0) {};
int yes;
};
#endif
object.cpp
#include <list>
#include "deleteme.h"
int main()
{
std::list<Object*> *pList;
Object *pObject;
pObject = new Object();
pList->push_front(pObject);
}
It causes a segfault because pList is not initialized.
std::list<Object*> *pList; // You declared it but you have not said what
// value lives here.
So when you try and use it:
pList->push_front(pObject); // This is undefined behavior.
If you turn your compiler warning on(up) the compiler will warn you this is a problem. You should really tell your compiler to treat all warnings as errors.
How do you solve it.
You should create a list.
std::list<Object*> *pList = new std::list<Object*>;
But creating it as a pointer is a bad idea (no a very bad idea). You have just opened up a hole can of worms that you don't want to handle. You should never (read hardly ever (or just never)) dynamically create memory. It leads to all sorts of problems with exceptions and leaks. Until you understand ownership semantics stick to objects.
std::list<Object> pList;
pList.push_back(Object());
In the comments you are worried about returning it from a function.
std::list<Object> getList()
{
std::list<Object> result;
result.push_back(Object());
result.push_back(Object());
return result;
}
int main()
{
// Technically this copies the list out of the function
// when the return is called (so your object and the list)
// must be copyable.
std::list<Object> data = getList();
// But in reality it will not be copied.
// Because the copiler will invoke NRVO and build it in place
// at the destination. If you put print statements in your objects
// constructor/destructor etc.. you can try and spot the copies.
// Turn on optimizations and any copies that did exist will be
// removed.
}
Related
Following is my code snippet. I am trying to write generic function to check whether pointer is valid and deleting it.
#include <windows.h>
#include <vector>
#include <map>
#include <string>
using namespace std;
struct testStruct
{
int nVal;
_TCHAR tcVal[256];
testStruct()
{
wmemset(tcVal, 0, _countof(tcVal));
}
};
void deletePointer(void *obj)
{
if (obj)
{
delete obj;
obj = NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
testStruct *obj = new testStruct;
wstring *strVal = new wstring();
vector<wstring> *vecVal = new vector<wstring>;
map<wstring,wstring> *mapVal = new map<wstring, wstring>;
//My business logic goes here.
//Finally after all business logic, clearing allocated memory.
deletePointer(obj);
deletePointer(strVal);
deletePointer(vecVal);
deletePointer(mapVal);
return 0;
}
While I am not facing any compilation or runtime error, just wanted to confirm, if this is the right way to check and delete multiple points. I don't want to check individual pointer whether it is valid or not before deleting. So calling generic function.
Thanks for your suggestions in advance.
Compilation and runtime errors are not present. Just need confirmation, if this is right way or is there a better way to do this.
No, it's both incorrect and unnecessary
If your compiler doesn't report error on this code, crank up warnings: https://godbolt.org/z/7ranoEnMa. Deleting a void* is Undefined Behaviour, you cannot predict what will be the result. If it's currently not crashing, it will likely crash at some random other use when you will least expect it.
It's unnecessary, because it's perfectly fine to delete nullptr; and your function only checks against that. If you wanted to check if the pointer is actually valid like Nathan Pierson suggests in comment (and you don't assign nullptr to them consistently), that's not possible. You are responsible for your memory management, no if can help if you don't do that correctly throughout the program.
And it's also not necessary, because memory management is already done for you. Containers shouldn't be ever allocated on the heap. Simply do
wstring strVal;
vector<wstring> vecVal;
map<wstring,wstring> mapVal;
And drop the pointers. C++ containers do all the magic by themselves and are generally small by themselves (sizeof(std::vector) is usually 3*sizeof(void*)).
Assuming you really need testStruct on the heap rather than in automatic storage, you should use a smart pointer:
std::unique_ptr<testStruct> obj = std::make_unique<testStruct>();
There, it's created, allocated on the heap and will be automatically deleted when obj ends its scope. You don't have to worry about deleteing anything anymore.
If you really want to have a function that deletes objects manually, it should look like this:
template <typename T>
void deletePointer(T*& obj)
{
delete obj;
obj = nullptr;
}
It keeps the type of the pointer to be deleted and updates passed pointer with nullptr, so it won't be invalid later on.
I’m a C++ beginner with a background in Python, Java, and JS, so I’m still learning the ropes when it comes to pointers.
I have a vector of shared pointers. Inside of a different function, I assign a shared pointer to a variable and add it to the vector. If I try to access the added element after that function exits, a segmentation fault happens:
class Bar
{
private:
std::vector<std::shared_ptr<Foo>> fooVector;
}
void Bar::addToFoo()
{
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);
}
void Bar::otherMethod()
{
// this method gets called sometime after addToFoo gets called
…
fooVector[anIndex]->baz(); // segfaults
…
}
But, if push_back a shared pointer and not a variable, it works.
// this works:
fooVector.push_back(std::shared_ptr<Foo>(new Foo(…)));
// this segfaults:
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);
I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I’m wrong). How do you push_back a shared_ptr variable to a vector of shared_ptrs in C++?
Why Use A Variable
Though pushing shared_ptrs to vectors directly without variables works, I prefer to use variables in order to do this:
std::shared_ptr<Rider> rider;
switch (iProcessorModesParam)
{
case PEAKS_MODE:
rider = std::shared_ptr<Rider>(new PeaksRider(…));
break;
case RMS_MODE:
rider = std::shared_ptr<Rider>(new RMSrider(…));
break;
}
volumeRiders.push_back(rider);
PeaksRider and RMSrider are subclasses of Rider. I want to store all subtypes of Rider in the same vector of Riders. I learned that adding subtypes of Rider to a vector of Riders doesn’t work and pointers are needed in order to achieve this kind of polymorphism:
std::vector<Rider> // doesn’t work with subtypes
std::vector<*Rider>
std::vector<std::shared_ptr<Rider>>
Having the std::shared_ptr<Rider> rider; variable avoids repeating the .push_back(…) code for each type of Rider.
Instead of assigning shared pointer, user reset method.
rider.reset(new PeaksRider(…));
other that this, your code snippets seems to okay to me.
segfault may have caused because of the index variable ( which may be out of range). i suggest you to use .at(index) for accessing pointer from vector and wrap that part of code in a try..catch block and see what is the real error.
And regarding...
I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I’m wrong).
This is not true, share_ptrs use a local counter for #of references. as soon as you pushed the pointer to vector the counter gets incremented to 2 and event after control exits the function the counter is decremented to 1. so, your object is not destroyed yet.
There is no problem on creating a shared pointer instance, storing it in a variable, and doing a push_back to a vector after that. Your code should be fine as long as the index that you use when calling "otherMethod" is valid. However, I have a couple of suggestions for your code:
When you create a shared_ptr, it is highly recommended to do it through "std::make_shared" to ensure the safety and correctness of your code in all situations. In this other post you will find a great explanation: Difference in make_shared and normal shared_ptr in C++
When accessing positions of a vector using a variable that may contain values that would cause an out-of-bounds access (which usually leads to segmentation faults) it is a good practice to place asserts before using the vector, so you will detect these undesired situations.
I just wrote a small snippet that you can test to illustrate what I just mentioned:
#include <iostream>
#include <vector>
#include <memory>
#include <cassert>
class Foo
{
public:
int data = 0;
};
class Bar
{
public:
void addNewFoo(int d)
{
std::shared_ptr<Foo> foo(new Foo());
foo->data = d;
fooVector.push_back(foo);
}
void addNewFooImproved(int d)
{
auto foo = std::make_shared<Foo>();
foo->data = d;
fooVector.push_back(foo);
}
void printFoo(int idx)
{
assert(idx < fooVector.size());
std::cout << fooVector[idx]->data << std::endl;
}
private:
std::vector<std::shared_ptr<Foo>> fooVector;
};
int main()
{
Bar b;
b.addNewFoo(10);
b.addNewFoo(12);
b.addNewFooImproved(22);
b.printFoo(1);
b.printFoo(2);
b.printFoo(0);
}
I'm using a library that, in order to construct some object that I use, expects a raw pointer to an object. I'm not sure what it will do with the pointer, to make my code as safe as possible, what should I pass to this function?
Use a unique pointer - if they decide to delete the pointer, I will do a double-delete
Keep track of a raw pointer - bad because I have to remember to write delete, but it could still be a double-delete
Use auto duration and give them a pointer Give them a reference - their code will error if they call delete
Use a shared pointer - same double-delete problem as unique pointer, but now my scope won't hurt their pointer
Based on my reading, option 3 seems like what I should do - they shouldn't be calling delete on the pointer, and this format enforces that. But what if I don't know whether they now or in the future will call delete on the reference I gave them? Use a shared pointer and say "not my fault about the double delete"?
#include <memory>
#include <iostream>
class ComplexObj {
public:
ComplexObj() : m_field(0) {}
ComplexObj(int data) : m_field(data) {}
void print() { std::cout << m_field << std::endl; }
private:
int m_field;
};
class BlackBox {
public:
BlackBox(ComplexObj* data) {
m_field = *data;
// Do other things I guess...
delete data;
std::cout << "Construction complete" << std::endl;
}
void print_data() { m_field.print(); }
private:
ComplexObj m_field;
};
int main(int argc, char* argv[]) {
// Use a smart pointer
std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
BlackBox obj1 = BlackBox(my_ptr.get());
obj1.print_data();
my_ptr->print(); // Bad data, since BlackBox free'd
// double delete when my_ptr goes out of scope
// Manually manage the memory
ComplexObj* manual = new ComplexObj(2);
BlackBox obj2 = BlackBox(manual);
obj2.print_data();
manual->print(); // Bad data, since BlackBox free'd
delete manual; // Pair new and delete, but this is a double delete
// Edit: use auto-duration and give them a pointer
ComplexObj by_ref(3);
BlackBox obj3 = BlackBox(&by_ref); // they can't call delete on the pointer they have
obj3.print_data();
by_ref.print();
// Use a shared pointer
std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
BlackBox obj4 = BlackBox(our_ptr.get());
obj4.print_data();
our_ptr->print(); // Bad data, they have free'd
// double delete when our_ptr goes out of scope
return 0;
}
Other questions I read related to this topic...
unique_ptr.get() is legit at times
I should pass by reference
I think I am case 2 and should pass by reference
You cannot solve this problem with the information you have. All choices produce garbage.
You have to read the documentation of the API you are using.
Doing any of your 4 answers without knowing if they take ownership of the pointer will result problems.
Life sometimes sucks.
If you have a corrupt or hostile API, the only halfway safe thing to do is to interact with it in a separate process, carefully flush all communication, and shut down the process.
If the API isn't corrupt or hostile, you should be able to know if it is taking ownership of the pointed to object. Calling an API without knowing this is a common mistake in novice C++ programmers. Don't do it. Yes, this sucks.
If this API is at all internal and you have any control, seek to make all "owning pointer" arguments be std::unique_ptr<>s. That makes it clear in the API that you intend to own the object and delete it later.
I am trying to print out value 123456, but it gives me the garbage value. How can I fix it? And Can you please explain why it gives the wrong value?
#include <stdio.h>
#include <stdlib.h>
struct MyInfo
{
private:
int private_key = 123456;
public:
int setkey(int value)
{
private_key = value;
}
int GetScore()
{
return private_key;
}
};
void main()
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo));
printf("%d\n", pMyInfo->GetScore());
free(pMyInfo);
}
Don't use malloc/free but rather pMyInfo = new MyInfo() and delete pMyInfo. Only new will call the constructor which initializes the value; only delete will call the destructor.
Regarding the comment, what is meant is, you can also have it on the stack, i.e. MyInfo pMyInfo;, i.e. not a pointer. That will automatically call the constructor and when it goes out of scope, the destructor.
int private_key = 123456;
This really is just a camouflaged constructor initialization which means it's the same as:
MyInfo() : private_key(123456) {}
Since malloc and friends are inherited from C and C has no classes (and thus no special member functions) whatsoever malloc and friends won't call these necessary special member functions to set up your object. The C++ equivalent new does however which is why you should always use new over malloc and delete over free.
But wait, there's more...
Actually, you shouldn't ever use new either, there are always better alternatives than using raw dynamic allocation. If you really need dynamic memory allocation then use std::unique_ptr or for multiple objects std::vector but most of the time you don't even need these ( there are tons of posts on here that explain when dynamic allocation is a must, for all the other cases just use storage with automatic lifetime) all you need in this case is a local object:
MyInfo myInfo;
printf("%d\n", myInfo.GetScore());
See how your code just got shorter, easier to maintain and cleaner to achieve the same?
When you declare a pointer of type MyInfo, it does not mean that the object it points to will actually be your struct, it just assumes it will be.
When you do malloc(sizeof(MyInfo)), you simply allocate memory of the size which your struct might take, it does not create an object. Hence, when you try to do GetScore(), it accesses memory location which it assumes contains your private_key, but instead it simply contains garbage.
Don't mix C and C++
You should avoid malloc/alloc etc in C++ and opt for new operator if you want to work with dynamically allocated objects.
Add a constructor to initialize the value
private;
int private_key;
public:
MyInfo () {
private_key = 123456;
}
And implement the main like
// without pointer
void main () {
MyInfo myinfo;
printf("%d\n", myinfo.GetScore());
}
// with pointer
void main () {
MyInfo *myinfo = new MyInfo();
printf("%d\n", myinfo->GetScore());
}
Just for reference, it is possible to initialize an object in raw storage, but it would be overkill and rather stupid for this use case. As malloc only allocate raw memory and does not construct an object, you could use a placement new to build the object in a second time:
int main() // I can't stand void main
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo)); // only allocate raw memory
new((void *) pMyInfo) MyInfo; // construct the object
std::cout << pMyInfo->GetScore() << std::endl; // no reason for C printf here
pMyInfo->~MyInfo(); // placement new requires explicit destructor call if not trivial
free(pMyInfo);
return 0;
}
DO NOT DO THAT for such a simple case. Placement new should only be used in very special cases where the allocation is not trivial, for example when you use share memory. But here the correct way is to simply use an automatic object:
int main() // I can't stand void main
{
MyInfo pMyInfo;
std::cout << pMyInfo.GetScore() << std::endl;
return 0;
}
Hi iam new to c++ and iam trying out this vector program and i am getting the following error:
error: conversion from test*' to non-scalar typetest' requested|
Here is the code
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
class test{
string s;
vector <string> v;
public:
void read(){
ifstream in ("c://test.txt");
while(getline(in,s))
{
v.push_back(s);
}
for(int i=0;i<v.size();i++)
{
cout<<v[i]<<"\n";
}
}
};
int main()
{
cout<<"Opening the file to read and displaying on the screen"<<endl;
test t=new test();
t.read();
}
new is used to dynamically allocate memory. You don't need to do that, so just do:
test t; // create an instance of test with automatic storage
t.read(); // invoke a method
The error is because the type of new test() is a test*, a pointer to a (newly created) test. You can't assign a test* to a test.
The pointer version, for what it's worth, would have been:
test* t = new test();
t->read(); // the arrow is short for (*test).
delete t; // don't forget to clean up!
However, it's bad style to do raw memory allocation like that. You'd use something called a smart pointer to make sure it gets deleted automatically, instead. The standard library has one in the header <memory>, called auto_ptr, that would suffice:
std::auto_ptr<test> t(new test()); // put a new test into a pointer wrapper
t->read(); // treat it like a normal pointer
// nothing else to worry about, will be deleted automatically
However, all this isn't needed for you, in this case. Always prefer automatic (stack) allocation over dynamic allocation.
Change
test t=new test();
t.read();
to
test *t=new test();
t->read();
t should be a pointer to type test. And to access a class member using a pointer we use the -> operator. Also its a good practice to delete any dynamically allocated objects as:
delete t;
new test() will return a pointer to a t so you either want to use pointer throuought or create t on the stack
Code using pointers
test *t=new test();
t->read(); // note needs -> rather than .
delete t; // as declared n the heap you must delete
or usually better do all on the stack
test t;
t.read();