C++ 使用std::shared_ptr<;无效>;指什么

C++ 使用std::shared_ptr<;无效>;指什么,c++,c++11,stl,shared-ptr,smart-pointers,C++,C++11,Stl,Shared Ptr,Smart Pointers,我在应用程序中使用了一个std::shared_ptr来制作一个智能指针,它可以指向许多不同类型的数据结构,如结构、向量、矩阵。。。基本上什么都可以。我要做的是将一些名称映射到它们的数据结构 我正在使用哈希表执行映射: std::无序地图 我是否可以将find()返回的std::shared_ptr转换回std::shared_ptr?如果是,怎么做 更重要的是,这是一种良好的做法吗?随着应用程序的扩展,这会不会增加太多的复杂性?或者,还有其他完全不同、优雅的方法吗 编辑 可能无法使用'Boos

我在应用程序中使用了一个
std::shared_ptr
来制作一个智能指针,它可以指向许多不同类型的数据结构,如结构、向量、矩阵。。。基本上什么都可以。我要做的是将一些名称映射到它们的数据结构

我正在使用哈希表执行映射:

std::无序地图

我是否可以将
find()
返回的
std::shared_ptr
转换回
std::shared_ptr
?如果是,怎么做

更重要的是,这是一种良好的做法吗?随着应用程序的扩展,这会不会增加太多的复杂性?或者,还有其他完全不同、优雅的方法吗

编辑

可能无法使用'Boost.Any',因为它使用RTTI

也不能对所有这些数据结构使用基类,因为其中一些是STL容器,如
std::vector

关于下面回答中讨论的
shared\u ptr
delete问题,我读到shared\u ptr执行类型擦除,并存储类型信息以知道调用哪个析构函数


但我对此不确定。

这不是一个好的做法。如果您没有在
std::shared_ptr
旁边存储额外的类型信息(您可以使用它进行转换),那么您的行为到处都是未定义的。也许这是你的选择


如果您想坚持使用
std::shared\u ptr
,请记住提供一个自定义的删除函数(请参阅)。

如果您存储
void*
,那么在每个使用点,您都需要知道您输入的确切类型,转换为-
void*
,并且只有在您转到/从完全相同的类型返回时才有效(例如,不是派生为从空到基)

考虑到每个使用点都需要知道存储指针的类型,为什么要往返于void呢

每个存储的类型有一个映射。这比每个应用程序有一个映射的开销要小(运行时的内存为O(类型数),编译时类似)

使用C++ >代码>模板< /C> >代码很少重复。 我可以将find()返回的std::shared\u ptr转换回std::shared\u ptr吗?如果可以,如何转换

是的。使用。也就是说,在这种情况下,您需要从void*转换为具体类型的事实很可能是设计不佳的症状

您应该(几乎)永远不需要从void*转换为强类型指针类型(“几乎”意味着我认为您永远不应该这样做,但可能有一些情况我没有考虑过)

更重要的是,这是一种良好的做法吗

不可以。根据经验,只有当您对内存地址的值感兴趣,而对存储的数据根本不感兴趣时,才应该转换为void*

随着应用程序的扩展,这会不会增加太多的复杂性

我能想到的第一个问题是,您的类型不再是在一个地方定义的。这意味着,如果到处都是指针强制转换,当您决定更改类名时,(或者您不再对路径使用std::string,而是使用boost::path对象,等等),则必须遍历所有代码并更新添加的所有强制转换中的所有类型

第二个问题是,随着应用程序的扩展,它会带来这个强制转换问题,并在代码库中传播它,使整个代码库的情况变得更糟因此,可维护性较差。如果在整个代码中存在其他设计折衷,超过一定大小,则应用程序将变得难以维护/禁止维护

这种方法只会使您无法编写松散耦合的代码

或者,还有其他完全不同、优雅的方法吗

检查代码并列出指针上使用的操作。然后,将这些操作作为纯虚拟函数添加到基类中。根据存储值类型实现该基类的具体模板专门化

代码:

class pointer\u holder{//获得更好的名称
公众:
虚空传送_指针()=0;//操作示例
虚拟~pointer_holder()=0;
};
模板
类类型\u持有者:公共指针\u持有者{
公众:
//TODO:添加构造函数等
虚空传送_指针(){
//为T实现远程传输\ U指针
}
虚拟~type_holder();
私人:
T值;
};
客户端代码:

std::unordered_map<std::string, std::shared_ptr<pointer_holder>> your_map;
your_map["int"] = new type_holder<int>{10};
your_map["string"] = new type_holder<std::string>{"10"};

your_map["int"]->teleport_pointer(); // means something different for each
                                     // pointer type
std::无序映射您的映射;
你的地图[“int”]=新的类型持有者{10};
你的地图[“字符串”]=新类型的持有者{“10”};
你的映射[“int”]->teleport_pointer();//对每一个元素都有不同的含义
//指针类型
您可以

#include <memory>
#include <iostream>
#include <string>

using namespace std;

class wild_ptr {
    shared_ptr<void> v;
public:
    template <typename T>
    void set(T v) {
        this->v = make_shared<T>(v);
    }

    template <typename T>
    T & ref() {
        return (*(T*)v.get());
    }
};

int main(int argc, char* argv[])
{
    shared_ptr<void> a;
    a = make_shared<int>(3);
    cout << (*(int*)a.get()) << '\n';
    cout << *static_pointer_cast<int>(a) << '\n'; // same as above

    wild_ptr b;
    cout << sizeof(b) << '\n';
    b.set(3);
    cout << b.ref<int>() << '\n';
    b.ref<int>() = 4;
    cout << b.ref<int>() << '\n';

    b.set("foo");
    cout << b.ref<char *>() << '\n';

    b.set(string("bar"));
    cout << b.ref<string>() << '\n';
    return 0;
}

您可能想看看。@JoachimPileborg谢谢您的建议,您能看看我对下面答案的评论吗?为什么RTTI是一个问题?您如何知道
map[“foo”]中存储的类型
?@DavidRodríguez dribeas在应用程序中,我确实知道映射到任何
foo
std::shared_ptr
的类型实际上并不调用UB。不是单独调用UB,而是将指针投射到另一个类型(即
p
指向
对象,但被投射到
派生的
)然后取消引用。@谢谢你,请你解释一下UB是如何被引入的。我也觉得我必须考虑Boost。任何一个暗示我的设计都有根本的缺陷。如果我没有错,Booost。任何一个都会引入基于动态的基于行为的行为,这真的是违背C++和它的致盲速度。@实际上现在正在看一些C代码,它使用了<代码> Value*/Cux>指针。但是我真的不想在C++中使用原始指针!使用<代码> STD::SysDypPTR <代码>,这对这里没有帮助。<代码>:STYD:PTR 只有当你有道具时才有意义。
#include <memory>
#include <iostream>
#include <string>

using namespace std;

class wild_ptr {
    shared_ptr<void> v;
public:
    template <typename T>
    void set(T v) {
        this->v = make_shared<T>(v);
    }

    template <typename T>
    T & ref() {
        return (*(T*)v.get());
    }
};

int main(int argc, char* argv[])
{
    shared_ptr<void> a;
    a = make_shared<int>(3);
    cout << (*(int*)a.get()) << '\n';
    cout << *static_pointer_cast<int>(a) << '\n'; // same as above

    wild_ptr b;
    cout << sizeof(b) << '\n';
    b.set(3);
    cout << b.ref<int>() << '\n';
    b.ref<int>() = 4;
    cout << b.ref<int>() << '\n';

    b.set("foo");
    cout << b.ref<char *>() << '\n';

    b.set(string("bar"));
    cout << b.ref<string>() << '\n';
    return 0;
}
3
3
8
3
4
foo
bar