I am new to C++11 so please be nice.
Could you show me an easy example, how a shared_ptr can replace standard pointer? I also appreciate, an explanation if it does not make sense in that case.
e.g. Could you transform this code?
std::vector <CVariant*>liste;
liste.push_back( new CVariant( (unsigned int) 24, Parameter1", TYPE_UINT) );
std::cout << liste.at(0)->get<int>() <<"\n";
delete liste.at(0);
->
std::vector < std::shared_ptr<CVariant> >liste;
???
If I'm not wrong you should do something like this:
std::vector<std::shared_ptr<CVariant>> liste;
liste.push_back( std::make_shared<CVariant> (arguments...));
Check this link
Hope this helps.
If you have a vector list like this
std::vector < std::shared_ptr<CVariant> >liste;
You should call the liste.push_back method with shared pointer instead of pointers. You can initialize shared pointers in c like this:
auto pointer = std::make_shared<CVariant>( (unsigned int) 24, Parameter1", TYPE_UINT );
Ant add the pointer to the list like this:
liste.push_back( pointer );
Related
in C++, if a method is accepting left reference + pointer only,
it seems it suffices if we only have a template method with T& as its parameter, why we usually overload with test(T* ) as well ?
proof of concept: left reference method can take pointer argument.
#include <iostream>
using namespace std;
template<class T>
void test(T& arg) {
T value = arg;
cout << *value << endl;
}
int main() {
int b = 4;
int* a = &b;
test(a); // compiles and runs without issue.
return 0;
}
Why [do] we usually overload with test(T* ) as well?
I am not sure that we usually do anything of the sort, but if one were to overload for a pointer, it would be because pointers behave differently than object types. Remember, a pointer in fact is not an object but an address to an object.
The reason that test(a) compiles and runs without issue is because it is accepting a reference to a pointer to an object as its parameter. Thus, when the line cout << *value << endl; executes, the pointer is dereferenced back to an object and we see 4 printed to standard out.
As #HolyBlackCat mentioned, we usually want do different things for T& and T*.
As indicated in the example, for test(T&) we usually need to manually do dereference, this would result in the difference in the behavior, so it makes sense to have a overload like this.
I was wondering if there is a way to access a data member within a struct that is being pointed to by a void*? What I'm trying to explain will hopefully be more apparent in my example code:
int main()
{
struct S
{
int val;
};
S s;
s.val = 5;
void* p;
p = malloc(sizeof(S));
*(struct S*) p = s;
std::cout<< *(struct S*)p.val << std::endl;
}
I have ran this exact code casting p as *(int*)p and it printed fine, however, using exact code above results in a compilation error. Haven't been able to find an example that quite accomplishes this task. Is it possible to access the data members of the struct after it is casted? why or why not? if so, how?
The . operator has higher precedence than a C-style cast. So *(struct S*)p.val is treated as *((struct S*)(p.val)), which doesn't make sense since p is a pointer and does not have members.
So you need parentheses to specify what you intended:
std::cout<< (*(struct S*)p).val << std::endl;
Or equivalently,
std::cout<< static_cast<S*>(p)->val << std::endl;
[But also: the statement *(struct S*) p = s; technically has undefined behavior, even though all most implementations will allow it. This is because C++ has rules about when an object is created, and there was no object of type S previously at that address, and assignment does not create an object except for some cases involving union members. A similar statement that does not have this problem would be new(p) S{s};.
Also also: use of malloc or void* is usually not a good idea in C++ in the first place. malloc should only be used when interfacing with a C library that requires it. Anything for which void* seems useful can probably be done more safely using templates. In a few cases a void* might be the only way to do something or "cleverly" avoid code duplication or something, but still use it sparingly and always with extreme caution.]
I defined an array of shared pointers called table as follows; now I want to make this table a shared pointer as well. however I am not sure how to do that. I appropriate help with that.
class Reference {
public:
int ref;
Reference (int r)
{
ref = r;
}
~Reference ()
{
cout << "destructor " << endl;
}
};
class segment
{
public:
std::shared_ptr < Reference > *table;
segment ()
{
table = new std::shared_ptr < Reference >[SIZE];
for (int i = 0; i < SIZE; i++)
{
table[i] = std::make_shared < Reference > (i);
}
}
};
Well, I'd say that
You probably don't need shared pointers in class segment at all.
Your table field is an area of fixed size (SIZE). If you're worried about its lifetime - just think about the lifetime of instances of segment. You can instantiate segments with a shared pointer, i.e. my_segment = std::make_shared<segment>(), and then pass that around even after going out of scope
Now, as for the multiple shared pointers being the contents of table: You are creating them altogether and will likely get rid of them altogether when you destroy the segment. Unless you're thinking of segment as a sort of an "hors d'oeuvre" plate from which others will copy different shared pointers, then you throw the plate away; that's not the case, is it? Assuming it isn't, just have a Reference table[SIZE] member, and be done with it.
Notes:
Your code actually has table be a raw pointer to shared-ptrs, which is probably not what you meant, since that's not what make_shared gives you.
You didn't say much about what the Reference type is about. That may have impact on this answer too; I'm ignoring its suggestive name.
I wrote simple code to help me understand smart pointers:
string s = "str";
vector <unique_ptr<string>> pv ;
pv.push_back(unique_ptr<string>(&s));
cout<<*(pv[0])<<endl;
This code compiles fine, but gets me a runtime error:
str
* Error in `...': munmap_chunk(): invalid pointer: 0x00007ffd956e57e0 * Aborted (core dumped)
What happened and what have I done wrong?
In the std::unique_ptr's destructor it will call delete on the &s pointer which was not allocated via new.
Just use:
std::vector<std::string> vector;
vector.emplace_back("str");
std::cout << pv[0] << std::endl;
There's no need for std::unique_ptr<std::string> there.
Your string is being destructed twice - once when your pv goes out of scope and is deleted, freeing all its contained unique_ptr elements, and once when s goes out of scope.
To use a vector of unique pointers (or to use unique pointers in general), it is essential that they are not aliased. So you could write:
auto *s = new std::string("str");
pv.push_back(std::unique_ptr<std::string>(s));
// do not write "delete s" anywhere...
Or, simpler and safer:
pv.push_back(std::make_unique<std::string>("str")); // make_unique is C++14
Or even:
std::unique_ptr<std::string> p{new std::string("str")};
pv.push_back(std::move(p));
// Do not attempt to use p beyond this point.
I ran into a problem with a dirty shutdown of my program, because of a shared pointer. I found a solution, but I'm not sure, if I have the right answer.
This is the minimalistic example:
double var;
boost::shared_ptr<const double> ptr1 (&var); // creates an invalid pointer on program exit
boost::shared_ptr<const double> ptr2 (new double); // works fine
int main (int argc, char **argv)
{
return 0;
}
Here is my answer which I would like to varify:
In the case of ptr1 the pointed-to object will be deleted before the pointer, which then points to an invalid address. But in the case of ptr2 the "smartness" of the shared pointer handles the issue above.
True?
Small extra question:
Is there a way to make ptr1 work (I tried reset()) or is that bad programming practice (if so why)?
Thanks for the clarification!
in the first case, the pointer isn't dynamically allocated, so the shared_ptr should not attempt to destroy the underlying object. that can be done by using a custom no-op deleter functor:
http://www.boost.org/doc/libs/1_51_0/libs/smart_ptr/sp_techniques.html#static