I'm learning to use std::any and std::any_cast, it's not working as I expected: after casting, the internal shared_ptr of casted object becomes empty.
Here is the simplified code to show the issue, it's hard for me to reason about why after inserting the pointer into the map, the pointed object has changed: shared_ptr no longer points to the original value and becomes empty. I'd love to learn why this behavior happens!
Note I am casting to pointer AA* and store the pointer in an unsorted map, since in real world case I cannot copy AA object, it's a workaround.
Thanks a lot!
struct AA {
std::shared_ptr<int> m_ptr = std::make_shared<int>(22);
int get() {
return *m_ptr;
}
};
struct Cache {
std::unordered_map<std::string, std::any> map;
void insert(std::string str) {
auto a_ptr = std::make_unique<AA>();
map[str] = std::make_any<AA*>(a_ptr.get());
// this casting works as expected, output is 22
auto casted = std::any_cast<AA*>(map[str]);
std::cout <<"inside insert: " << casted->get() << std::endl;
}
};
int main(int argc, char** argv) {
Cache cache;
cache.insert("aa");
auto data = std::any_cast<AA*>(cache.map["aa"]);
// this won't work, output is 0, why?
std::cout << "in main: " << data->get() << std::endl;
}
godbolt demo
Related
I'm having the following code, but after run the code, the result is empty, any ideas why the result is empty? the reference of result in function main was passed to myclass, I thought function addToResult will actually add data to result, and I'm expecting a map key = "test", value = "1": "1". I'm kind of new to c++. Thanks!
#include <iostream>
#include <string>
#include <unordered_map>
using LookUpTable = std::unordered_map<std::string, std::string>;
using DLTable = std::unordered_map<std::string, LookUpTable>;
class MyClass
{
public:
MyClass(DLTable& dltable) {
m_dltable = dltable;
};
void addToResult() {
LookUpTable ee;
ee.emplace("1", "1");
m_dltable.emplace("test", ee);
};
private:
DLTable m_dltable;
};
int main ()
{
DLTable result;
MyClass myclass(result);
myclass.addToResult();
std::cout << "myrecipe contains:" << std::endl;
for (auto& x: result) {
std::cout << x.first << ": "<< std::endl;
for (auto& xx : x.second) {
std::cout << xx.first << ": " << xx.second << std::endl;
}
}
std::cout << std::endl;
return 0;
}
Let' look into simplified example:
int a = 0;
int &b = a;
int c = b;
c = 123;
Will last assignment modify a? Of course not. It does not matter how you pass value to c through reference or not c is completely independent variable that just initialized by a reference.
Your case is the same - m_dltable is separate variable and the fact you initialize it using reference does not change anything. (Your case even worse, you did not initialize it by reference, you assigned to it)
In general your approach is wrong. If you want directly access that variable then just make it public, do not try to create convoluted workarounds on how to access it. If you want incapsulation just create members that allow you to iterate over that container. For example return a const reference to it or have begin() and end() methods that return (const) iterators accordingly.
So I'm working on a text-based RPG, and I've run into an issue. I am currently working on equipping weapons from the character's inventory. I am trying to make it so that my program can tell if the item they want to equip is of class Weapon or not. Here is the clip of relevant code:
Item tempChosenWeapon = myInventory.chooseItem();
cout << tempChosenWeapon.getName() << endl;
Item *chosenWeapon = &tempChosenWeapon;
cout << chosenWeapon->getName() << endl;//THE CODE WORKS UP TO HERE
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
cout << maybeWeapon->getName() << endl;
Now, Weapon is a child class of Item, which is why I am using dynamic cast -- in an attempt to change chosenWeapon, which is of type Item, to type Weapon in order to compare the two classes. (I am using these cout<<s in or to test whether or not calling a function from these objects works).
My program compiles, and everything runs fine until we come to maybeWeapon->getName(), in which the program crashes. I've researched quite a bit, but I just don't understand what I am doing wrong. Any answer or alternative suggestion is much appreciated! Thanks!
The problem
The problem is that you try to make a dynamic cast to a Weapon but in reality the object pointed to is a true copy constructed Item and not a subclass. This is results in a nullptr and UB when you dereference it !
Why ?
Let's suppose that you have only Weapon objects in your inventory. The first instruction in your snippet is the root of your evil:
Item tempChosenWeapon = myInventory.chooseItem();
This is statement is a copy construction of an Item object. If the source object was a Weapon, it will be sliced.
Later you take a pointer to this object:
Item *chosenWeapon = &tempChosenWeapon;
But this Item* doesn't point to a Weapon object as you think. It points to a real crude Item object ! So when you do the dynamic cast here:
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
the code will find out that choosenWeapon is not a Weapon*, and the result of dynamic_cast will be a nullptr. Until now it's not necessarily a catastrophe. But when you then derefence this pointer you get UB:
maybeWeapon->getName() // OUCH !!!!!!
Solution
Checking if the dynamic_cast was successful (i.e. result not nullptr) is a protection against the crash, but will not solve your root problem.
It is even possible that the problem is even deeper than expected: what type does the myInventory.chooseItem() return in reality ? Is it a plain Item ? Then you might have the slicing problem already in the inventory !
If you want to use polymorphism:
you have to work with pointers (preferably smart pointers) or with references, in order not to loose the original type of an object, like it happened here.
If you need to copy polymorphic objects, you can't just use an assignment with an Item: you'd need to invoke a polymorphic clone() function and ensure that the target of this cloning has a compatible type.
To start with a solution, it's something like this:
Item* chosenWeapon = myInventory.chooseItem(); // refactor choosItem() to return a pointer.
cout << chosenWeapon->getName() << endl;
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
if (maybeWeapon)
cout << maybeWeapon->getName() << endl;
else cout << "Oops the chosen item was not a weapon" <<endl;
If this still not work, then your inventory container would be flawed. In this case, look at this question before opening a separate question with the code of your container
dynamic_cast will return nullptr if the pointer cast cannot be performed (for reference casts it will throw an exception), so your code should read something like:
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
if ( maybeWeapon ) {
cout << maybeWeapon->getName() << endl;
else {
// it's not a weapon
}
If you don't perform that test, and try to dereference the pointer containing nullptr, you are off in Undefined Behaviour Land.
Item tempChosenWeapon = myInventory.chooseItem();
this is an Item. Not a type descended from Item. It is an Item.
Values in C++ have known types.
cout << tempChosenWeapon.getName() << endl;
all good, but please stop using namespace std;
Item *chosenWeapon = &tempChosenWeapon;
This is a pointer to an Item. I can prove it is not polymorphic, because it is a pointer to a instance of type Item. The compiler can probably prove it to.
cout << chosenWeapon->getName() << endl;//THE CODE WORKS UP TO HERE
ok, this repeats the previous call.
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
This deterministically returns nullptr. chosenWeapon is an Item* that we know points to an Item, and an Item is not a Weapon.
cout << maybeWeapon->getName() << endl;
this dereferences nullptr.
There are a number of ways to handle polymorphism in C++. But you have to think about it.
First, do you want value semantics? Value sematnics means that a copy of something is a copy of it. Things don't refer to other things; they are those things.
You can do value semantics with polymorphic values, but it takes a bit of work. You write two classes; the value wrapper, and the internal pImpl.
The internal pImpl has a std::unique_ptr<Impl> Impl->clone() const method, and the value wrapper calls it when you copy it.
You write your interface like this:
template<class D>
struct clonable {
std::unique_ptr<D> clone() const = 0;
};
struct ITarget;
struct IItem:clonable<IItem> {
virtual std::string get_name() const = 0;
virtual bool can_equip( ITarget const& ) const = 0;
~virtual IItem() {}
};
struct Target;
struct Item {
using Impl = IItem;
explicit operator bool() const { return (bool)pImpl; }
IItem* get_impl() { return pImpl.get(); }
IItem const* get_impl() const { return pImpl.get(); }
template<class D>
D copy_and_downcast() const& {
auto* ptr = dynamic_cast<typename D::Impl const*>( pImpl.get() );
if (!ptr) return {};
return D(ptr->clone());
}
template<class D>
D copy_and_downcast() && {
auto* ptr = dynamic_cast<typename D::Impl*>( pImpl.get() );
if (!ptr) return {};
pImpl.release();
return D(std::unique_ptr<typename D::Impl>(ptr));
}
std::string get_name() const {
if (!*this) return {};
return pImpl->get_name();
}
bool can_equip(Target const& target)const{
if (!*this) return false;
if (!target) return false;
return pImpl->can_equip( *target.get_impl() );
}
Item() = default;
Item(Item&&) = default;
Item& operator=(Item&&) = default;
Item(std::unique_ptr<IItem> o):pImpl(std::move(o)) {}
Item(Item const& o):
Item( o?Item(o.pImpl->clone()):Item{} )
{}
Item& operator=( Item const& o ) {
Item tmp(o);
std::swap(pImpl, tmp.pImpl);
return *this;
}
private:
std::unique_ptr<IItem> pImpl;
};
which probably has bugs and is maybe too complex for you.
Second, you can go with reference semantics.
In this case, you want to return shared_ptr<const T> or shared_ptr<T> from your data. Or you can go half way and return a unique_ptr<T> copy from your chooseItem functions.
Reference semantics is really hard to get right. But you do get to use dynamic_cast or dynamic_pointer_cast directly.
std::shared_ptr<Item> chosenWeapon = myInventory.chooseItem();
if (!chosenWeapon) return;
std::cout << chosenWeapon->getName() << std::endl;
auto maybeWeapon = dynamic_pointer_cast<Weapon>(chosenWeapon);
if (maybeWeapon)
std::cout << maybeWeapon->getName() << std::endl;
else
std::cout << "Not a weapon" << std::endl;
You cannot cast an object of type Item to an object of a subclass of Item.
Note that with Item tempChosenWeapon = myInventory.chooseItem(), you will get an Item-object, even if chooseItem might return a Weapon-object. This is called "slicing" and cuts out an Item-subobject of any Weapon-object. Note that variables that are not references or pointers are not polymorphic:
struct A {
int a = 0;
virtual void print() const {
std::cout << "a:" << a << std::endl;
}
};
struct B : public A {
int b = 1;
void print() const override {
std::cout << "a:" << a << "; b:" << b << std::endl;
}
};
B b;
A get_b() { // will slice b;
return b;
}
A& getRefTo_b() { // reference to b; polymorphic
return b;
}
A* getPointerTo_b() { // pointer to b; polymorphic.
return &b;
}
int main() {
A a1 = get_b(); // copy of A-subobject of b; not polymorphic
a1.print();
// a:0
A a2 = getRefTo_b(); // copy of A-subobject of referenced b-object; not polymorphic
a2.print();
// a:0
A &a3 = getRefTo_b(); // storing reference to b-object; polymorphic
a3.print();
// a:0; b:1
A *a4 = getPointerTo_b(); // pointer to b-object; polymorphic
a4->print();
// a:0; b:1
B* b1 = dynamic_cast<B*>(&a1); // fails (nullptr); a1 is not a B
B* b2 = dynamic_cast<B*>(&a2); // fails (nullptr); a2 is not a B
B* b3 = dynamic_cast<B*>(&a3); // OK; a3 refers to a B-object
B* b4 = dynamic_cast<B*>(a4); // OK; a4 points to a B-object
return 0;
}
So your signature should probably be
Item &Inventory::chooseItem() {
static Weapon weapon;
...
return weapon;
};
int main() {
Item &myWeapon = myInventory.chooseItem();
Weapon* w = dynamic_cast<Weapon*>(&myWeapon);
...
}
I need to keep reference of an object passed into a thread. The way the environment is setup I must keep application specific drawing in the same thread it was initiated. So I tuck away app init code in a thread and then get a reference to a custom component I'm interested in.
This isn't working. The app loads and shows up fine but the pointer to the app in the main thread is always null. Even if I use std::shared_ptr or std::ref. Doesn't seem to matter what I do, the pointer is always null.
#include <thread>
#include <iostream>
class SomeClass {
public:
int value;
SomeClass() { value = 0; }
};
void ExecuteThread(SomeClass* c) {
c = new SomeClass();
c->value = 555;
}
int main(int argc, char** argv) {
SomeClass* c = nullptr;
// std::ref(c) doesn't work
// Have also tried passing std::shared_ptr<SomeClass>
std::thread t1 = std::thread(&ExecuteThread, c);
t1.join();
std::cout << "c: " << c << "\n";
std::cout << "c->value: " << c->value << "\n";
return 0;
}
Just so that people do not get confused by incorrect self-answer, I am providing my own, correct answer.
The prime issue with OPs code is the fact that passing pointer by value copies the pointer, and any modification to it will not affect the original. Threads do not change this fact, and do add nothing to it. In particular, the code can be illustrated as
void change(int* k) {
k = nullptr;
}
int i;
k = &i;
change(k);
// k here is still the same as before calling `change`
If one wants to change passed pointer, it should be passed as a reference: void change(int*& k).
Having threads here changes things slightly. Since there is no way to pass something to a std::thread constructor by reference, std::ref needs to be used. The function signature should still accept pointer by reference, and std::ref should be used where thread is created:
auto t = std::thread(change, std::ref(k))
std::thread secretly makes copies of everything you pass as an argument including pointer data. This is incredibly misleading. The only way around that is to pass an address to a pointer and have the thread copy that. Then in your thread's task, deference to a pointer.
#include <thread>
#include <iostream>
class SomeClass {
public:
int value;
SomeClass() { value = 0; }
};
void ExecuteThread(SomeClass** c) {
*c = new SomeClass();
*c->value = 555;
}
int main(int argc, char** argv) {
SomeClass* c = nullptr;
std::thread t1 = std::thread(&ExecuteThread, &c);
t1.join();
std::cout << "c: " << c << "\n";
std::cout << "c->value: " << c->value << "\n";
return 0;
}
I have some code that claims ownership of a sequence of raw pointers, and am wondering if there is an acceptable way to do this? What I'm looking for is a way to enforce the ownership in code to a greater degree. Mainly, I've been wondering whether or not my constructor should be taking a vector of unique pointers directly.
As a sidenote, once ownership has been claimed, the data is supposed to be immutable.
The code follows roughly the pattern of class X below.
#include <iostream>
#include <memory>
#include <vector>
using namespace std; // For readability purposes only
class X {
public:
const vector< unique_ptr<const int> > data; // In my case this is private
// Constructor: X object will take ownership of the data
// destroying it when going out of scope
X (vector<int*> rawData)
: data { make_move_iterator(rawData.begin()), make_move_iterator(rawData.end()) }
{ }
};
int main() {
// Illustrating some issues with claiming ownership of existing pointers:
vector<int*> rawData { new int(9) , new int(4) };
int* rawPointer = rawData[0];
{ // New scope
X x(rawData);
cout << *(x.data[0]) << endl; // Unique pointer points to 9
*rawPointer = 7;
cout << *(x.data[0]) << endl; // Unique pointer points to 7
}
cout << *rawPointer << endl; // The pointer has been deleted, prints garbage
return 0;
}
It is difficult to post an answer without detailed knowledge of your situation. But my recommendation is to attach your data to a unique_ptr as soon as it is known. Then you can move that unique_ptr into and out of vectors at will. For example:
#include <iostream>
#include <memory>
#include <vector>
using namespace std; // For readability purposes only
class X {
public:
const vector< unique_ptr<const int> > data; // In my case this is private
// Constructor: X object will take ownership of the data
// destroying it when going out of scope
X (vector<unique_ptr<const int>>&& v)
: data { std::move(v) }
{ }
};
vector<unique_ptr<const int>>
collectRawData()
{
auto rawData = {9, 4};
vector<unique_ptr<const int>> data;
for (auto const& x : rawData)
data.push_back(make_unique<int>(x));
return data;
}
int main() {
auto rawData = collectRawData();
{ // New scope
X x(std::move(rawData));
cout << *(x.data[0]) << endl; // Unique pointer points to 9
cout << *(x.data[1]) << endl; // Unique pointer points to 4
}
}
You did several misstakes.
In case of const vector< unique_ptr<const int> > data; a move iterator does make not that much sense. The reason why is, int* doesn't have a move constructor.
If you call X's constructor X (vector<int*> rawData) with vector < int* > so the copy constructor of vector < int* > gets called, but that's not what you want to.
Btw. the reason why to use move is, to avoid big memory copies. For instance std::vector < int* >: The member attribute size and the pointer to the memory location where your int*s are stored of std::vector<int*> must be copied by a move too but not the int*s self. A conclusion is that move is there to claim ownership.
If you want shared pointers like that, use std::shared_ptr. It owns a counter, which counts the ptrs which pointing to itself.
ยด
My Example Code:
class X
{
public:
const std::vector< std::shared_ptr< const int> > data; // In my case this is private
// Constructor: X object will take ownership of the data
// destroying it when going out of scope
X (std::vector<std::shared_ptr<int>>& rawData)
//: data(rawData)
: data(rawData.cbegin(), rawData.cend())
{ }
};
int main() {
// Illustrating some issues with claiming ownership of existing pointers:
std::vector<std::shared_ptr<int>> rawData { std::make_shared<int>(9), std::make_shared<int>(4) };
int* rawPointer = rawData[0].get();
{ // New scope
X x(rawData);
cout << *(x.data[0]) << endl; // Unique pointer points to 9
*rawPointer = 7;
cout << *(x.data[0]) << endl; // Unique pointer points to 7
}
cout << *rawPointer << endl; // The pointer has been deleted, prints not more garbage
return 0;
}
If you dont want use std::shared_ptr, you will need an GC.
Here is my problem: sometimes I have an std::string defined in a function. I need to extend the scope of the string because of an asynchronous operation. Naturally I can copy it into a shared pointer like this:
{
std::string hi{"hi"};
auto shared_hi = std::make_shared<std::string>(hi);
//insert shared_hi in async queue
}
The problem with this is that sometimes my strings are very very very big, and sometimes they are vectors, and sometimes they are std::arrays. so not only would I like to avoid a copy, but I would also like to have a function that can "steal" the data out of containers without having to copy them. I've come up with a clever solution posted below, but I'm wondering if there isn't a better solution to this. If there isn't, I'd like to know if doing what I'm doing below is defined behavior:
template<class T>
class WrappedDeleter {
public:
WrappedDeleter(T &&other): o_(std::move(other)) {
}
private:
T o_;
};
//This function creates a deleter where the scope
template<class P, class T>
std::function<void(P *)> make_delete(T &&encapsulate) {
WrappedDeleter<T> *d = new WrappedDeleter<T>(std::move(encapsulate));
return [d](P * ptr) {
std::cout << "deleting now\n";
delete d;
};
}
template<class P, class C>
std::shared_ptr<P> steal_data(C &&data) {
P *ptr = data.data();
//can't use make_shared - custom deleter
return std::shared_ptr<P>(ptr, make_delete<P, C>(std::move(data)));
}
used like this:
int main() {
{
std::shared_ptr<int> p_a;
std::shared_ptr<int> p_b;
std::shared_ptr<const char> p_c;
{
std::array<int,3> a= {{1,2,3}};
std::vector<int> b= {1,2,3};
std::string c= {"hello world"};
p_a = steal_data<int,std::array<int,3> >(std::move(a));
p_b = steal_data<int, std::vector<int> >(std::move(b));
p_c = steal_data<const char, std::string>(std::move(c));
std::cout << "inside" << *p_a << " " << *p_b << " " << p_c.get() << std::endl;
}
std::cout << "outside" << *p_a << " " << *p_b << " " << p_c.get() << std::endl;
std::cout << "end of scope\n";
}
return 0;
}
As Praetorian says, the only sensible way to move data into a shared_ptr is using make_shared<T>(move(obj)). If you want the shared_ptr to point to the underlying contiguous data block rather than the container itself, you can use the alias constructor template<class Y> shared_ptr(const shared_ptr<Y>& r, T *ptr);:
std::vector<int> v{1, 2, 3};
auto cptr = std::make_shared<std::vector<int>>(std::move(v));
std::shared_ptr<int> ptr{cptr, cptr->data()};
As a function:
template<typename Container>
std::shared_ptr<Container::value_type> steal_data(Container &&cont) {
auto cptr = std::make_shared<Container>(std::move(cont));
return {cptr, cptr->data()};
}