emplace_back with pointer and unique pointers - c++

In relation to someFunctionOne and someFunctionTwo.
Is the end result still the same when each is emplaced into the map ?
Does the pointer get upgraded to a smart pointer ?
struct MyStruct {
int x = 0;
};
std::unordered_map<int, std::unique_ptr<MyStruct>> m_map;
void someFunctionOne(int id, std::unique_ptr<MyStruct>& myStruct){
m_map.emplace(id, std::move(myStruct));
}
void someFunctionTwo(int id, MyStruct * myStruct){
m_map.emplace(id, myStruct);
}
int main()
{
someFunctionOne(452, std::make_unique<MyStruct>());
someFunctionTwo(10, new MyStruct);
m_map.clear();
return 0;
}

Does the pointer get upgraded to a smart pointer ?
The correct term is Implicit type conversion. But yes, that is what would happen in this line:
m_map.emplace(id, myStruct);
This is because unique_pointer has a single value constructor which has the signature:
explicit unique_ptr( pointer p ) noexcept;
This is what would be called to convert the pointer to a unique_ptr.

Related

swap function not works as expectd [duplicate]

I have my function and I am filling targetBubble there, but it is not filled after calling this function, but I know it was filled in this function because I have there output code.
bool clickOnBubble(sf::Vector2i & mousePos, std::vector<Bubble *> bubbles, Bubble * targetBubble) {
targetBubble = bubbles[i];
}
And I am passing the pointer like this
Bubble * targetBubble = NULL;
clickOnBubble(mousePos, bubbles, targetBubble);
Why it is not working?
Because you are passing a copy of pointer. To change the pointer you need something like this:
void foo(int **ptr) //pointer to pointer
{
*ptr = new int[10]; //just for example, use RAII in a real world
}
or
void bar(int *& ptr) //reference to pointer (a bit confusing look)
{
ptr = new int[10];
}
You are passing the pointer by value.
Pass a reference to the pointer if you want it updated.
bool clickOnBubble(sf::Vector2i& mousePos, std::vector<Bubble *> bubbles, Bubble *& t)
if you write
int b = 0;
foo(b);
int foo(int a)
{
a = 1;
}
you do not change 'b' because a is a copy of b
if you want to change b you would need to pass the address of b
int b = 0;
foo(&b);
int foo(int *a)
{
*a = 1;
}
same goes for pointers:
int* b = 0;
foo(b);
int foo(int* a)
{
a = malloc(10); // here you are just changing
// what the copy of b is pointing to,
// not what b is pointing to
}
so to change where b points to pass the address:
int* b = 0;
foo(&b);
int foo(int** a)
{
*a = 1; // here you changing what b is pointing to
}
hth
You cannot change the pointer unless you pass it by (non const) reference or as a double pointer. Passing by value makes a copy of the object and any changes to the object are made to the copy, not the object. You can change the object that the pointer points to, but not the pointer itself if you pass by value.
Have a read of this question to help understand the differences in more detail When to pass by reference and when to pass by pointer in C++?

Why is pointer dropping value in C++? [duplicate]

I have my function and I am filling targetBubble there, but it is not filled after calling this function, but I know it was filled in this function because I have there output code.
bool clickOnBubble(sf::Vector2i & mousePos, std::vector<Bubble *> bubbles, Bubble * targetBubble) {
targetBubble = bubbles[i];
}
And I am passing the pointer like this
Bubble * targetBubble = NULL;
clickOnBubble(mousePos, bubbles, targetBubble);
Why it is not working?
Because you are passing a copy of pointer. To change the pointer you need something like this:
void foo(int **ptr) //pointer to pointer
{
*ptr = new int[10]; //just for example, use RAII in a real world
}
or
void bar(int *& ptr) //reference to pointer (a bit confusing look)
{
ptr = new int[10];
}
You are passing the pointer by value.
Pass a reference to the pointer if you want it updated.
bool clickOnBubble(sf::Vector2i& mousePos, std::vector<Bubble *> bubbles, Bubble *& t)
if you write
int b = 0;
foo(b);
int foo(int a)
{
a = 1;
}
you do not change 'b' because a is a copy of b
if you want to change b you would need to pass the address of b
int b = 0;
foo(&b);
int foo(int *a)
{
*a = 1;
}
same goes for pointers:
int* b = 0;
foo(b);
int foo(int* a)
{
a = malloc(10); // here you are just changing
// what the copy of b is pointing to,
// not what b is pointing to
}
so to change where b points to pass the address:
int* b = 0;
foo(&b);
int foo(int** a)
{
*a = 1; // here you changing what b is pointing to
}
hth
You cannot change the pointer unless you pass it by (non const) reference or as a double pointer. Passing by value makes a copy of the object and any changes to the object are made to the copy, not the object. You can change the object that the pointer points to, but not the pointer itself if you pass by value.
Have a read of this question to help understand the differences in more detail When to pass by reference and when to pass by pointer in C++?

implicitly convert std::shared_ptr to a type

Let's say I have a class A which specifies conversion to int
struct A {
int val = 42;
operator int() const {
return val;
}
so I can use it like this:
A a;
int a_int = a;
But what if I want to use shared pointer to the class:
auto a_ptr = std::shared_ptr<A>(new A);
int a_int = a_ptr; // ???
Just like the variable with type A was implicitly converted to int I want to do the same with a smart pointer.
How can I achieve that?
UPDATE
I'm sorry maybe I asked wrong way.
The real deal is a little bit more complicated.
I use QVariant to hold std::shared_ptr.
for now I have a helper function to do that:
QVariant & operator<< (QVariant& v, const std::shared_ptr<A> & aPtr);
When I need to place my pointer to QVariant I do this:
QVariant variant = QVariant() << a_ptr;
But I want to do it automatically, something like this:
QVariant variant = a_ptr;
Have you tried it?
std::shared_ptr has the operator* and it works as one can expect: use it.
#include <memory>
struct A {
int val = 42;
operator int() const {
return val;
}
};
int main() {
auto ptr = std::make_shared<A>();
int v = *ptr;
}
Just like the variable with type A was implicitly converted to int I want to do the same with a smart pointer.
No, you think you do, but you really don't.
How can I achieve that?
You can't, and that's a good thing.
(anticipating) Any way around it?
Wrap the shared pointer into an object, like this:
#include <memory>
template<class T>
struct shared_reference
{
shared_reference(std::shared_ptr<T> pt) : _pt(std::move(pt)) {}
operator T& () {
return *_pt;
}
operator const T& () const {
return *_pt;
}
std::shared_ptr<T> _pt;
};
Its quite simple, use dereference operator:
int a_int = *a_ptr; // ???
^ ~~~
[Edit]
To make:
QVariant variant = a_ptr;
Work, You would have to add to QVariant copy constructor accepting reference to shared_ptr. And this is something you cannot do. Such statement is called Copy Initialization, first compiler tries to do conversion of a_ptr to QVariant and if it is available then copy constructor of QVariant is called with converted a_ptr. The problem is that even if you dereference a_ptr, there are two user defined conversions needed.
You can still add a cast like here:
QVariant variant = static_cast<int>(*a_ptr);

C++ 11: conversion const int* to int* using unordered_set::push

I have this problem of conversion with this code using c++11 standard:
#include<unordered_set>
struct B
{
int x, y;
};
class A
{
struct hash
{
std::size_t operator()( int* const a ) const
{
return std::hash<int>()( *a );
}
};
struct equal_to
{
std::size_t operator()( int* const a, int* const b ) const
{
return std::equal_to<int>()( *a, *b );
}
};
private:
std::unordered_set< int*, hash, equal_to > set;
public:
void push( const B& b )
{
set.insert( &b.x );
}
};
Anyone know why is that? I can I solve the problem removing the "const" modifier in the argument of "push". But I don't want it because argument "b" isn't modified.
Edit.: My simplification of code has produced a unreferenced adress. I've make a struct B remove it.
The key of the set is declared as being a pointer-to-int, an int*. But this:
void push( const B& b )
{
set.insert( &b.x );
}
is passing the address of a constant int, an int const*, hence the compiler error.
Removing the const from the argument would resolve the compiler error, as would making the key type an int const*, but both these solutions would:
permit some other part of the program, with non-const access to a B instance that was passed to push(), to change a value of one of the keys within the set and break the set invariant:
A a;
B b1{17, 22};
B b2{30, 22};
a.push(b1);
a.push(b2);
b1.x = 30; // set no longer contains unique keys.
introduce a dependency of the set on the lifetime of the object referenced by b:
A a;
a.push({14, 23}); // a now contains a dangling pointer.
The safest solution is to store an int as the key, see http://ideone.com/KrykZw for online demo (thanks to bitmask for comment).
Possible solutions:
Dynamically copy b.x. Or,
Use int const* as the key. Or preferably (avoiding explicit dynamic allocation),
Use int as the key, instead of an int* (see http://ideone.com/KrykZw)

Function does not change passed pointer C++

I have my function and I am filling targetBubble there, but it is not filled after calling this function, but I know it was filled in this function because I have there output code.
bool clickOnBubble(sf::Vector2i & mousePos, std::vector<Bubble *> bubbles, Bubble * targetBubble) {
targetBubble = bubbles[i];
}
And I am passing the pointer like this
Bubble * targetBubble = NULL;
clickOnBubble(mousePos, bubbles, targetBubble);
Why it is not working?
Because you are passing a copy of pointer. To change the pointer you need something like this:
void foo(int **ptr) //pointer to pointer
{
*ptr = new int[10]; //just for example, use RAII in a real world
}
or
void bar(int *& ptr) //reference to pointer (a bit confusing look)
{
ptr = new int[10];
}
You are passing the pointer by value.
Pass a reference to the pointer if you want it updated.
bool clickOnBubble(sf::Vector2i& mousePos, std::vector<Bubble *> bubbles, Bubble *& t)
if you write
int b = 0;
foo(b);
int foo(int a)
{
a = 1;
}
you do not change 'b' because a is a copy of b
if you want to change b you would need to pass the address of b
int b = 0;
foo(&b);
int foo(int *a)
{
*a = 1;
}
same goes for pointers:
int* b = 0;
foo(b);
int foo(int* a)
{
a = malloc(10); // here you are just changing
// what the copy of b is pointing to,
// not what b is pointing to
}
so to change where b points to pass the address:
int* b = 0;
foo(&b);
int foo(int** a)
{
*a = 1; // here you changing what b is pointing to
}
hth
You cannot change the pointer unless you pass it by (non const) reference or as a double pointer. Passing by value makes a copy of the object and any changes to the object are made to the copy, not the object. You can change the object that the pointer points to, but not the pointer itself if you pass by value.
Have a read of this question to help understand the differences in more detail When to pass by reference and when to pass by pointer in C++?