通过make_unique取消引用下转换的派生对象是否安全

Is it safe to dereference a downcasted derived object via make_unique?

本文关键字:派生 对象 是否 安全 转换 make unique 取消 引用 通过      更新时间:2023-10-16

我有一个基类和一个派生类,以及一个返回基类引用的函数。使用make_unique然后向下转换指针安全吗?

我正在努力避免复制操作。

class Animal {}
class Dog : Animal {}
Animal GetAnimal() { ... }
Dog GetDog() {
   Dog dog = *std::make_unique<Dog>( GetAnimal() );
   return dog;
}

或者有更直接的方法吗?

编辑:

这是实际的代码(非常接近我上面显示的内容:

// Convert from (m)anaged to (u)nmanaged Title 
Title Data::MarshalTitle(TitleMap ^mdefn) {
    Title udefn = MarshalValue(mdefn);
    return udefn;
}

然后MarshalValue定义为:

Value Data::MarshalValue(TitleMap ^mdefn)

现在,您在这里没有看到Value是一个基类,Title是一个派生类。

我从编译器得到的错误是:

error C2440: 'initializing' : cannot convert from 'Definitions::Value' to 'Definitions::Title'  D:ProjectsParsersView.cpp

Intellisense告诉我,没有合适的用户定义的从值到标题的转换。

然而,这可以很好地通过编译器,但我不确定这是否安全。

// Convert from (m)anaged to (u)nmanaged Title Dimension definition
Title Data::MarshalTitle(TitleMap ^mdefn) {
    Title udefn = *std::make_unique<Title>(MarshalValue(mdefn));
    return udefn;
}

你的问题不是你认为的那样。您感到困惑,因为您的代码意味着继承是私有的,并且等价于以下内容:

class Dog : private Animal {}

有了私人遗产,你的狗就不是动物了。

而您真正想要的是常规继承:

class Dog : public Animal {}

然后你实际上不需要向下转换任何内容,因为C++会为你做这件事。

有了公共继承,以下内容将在没有任何副本的情况下工作:

void myFun(Animal&);
int main() {
    Dog dog;
    myFun(dog);
}

好的,我找到了原来问题的答案。简而言之:这样做是不安全的。它绕过了铸件评估,并且在运行时会吹坏垫圈。

由于嵌套派生类的数量,而其中一个位于中间的派生类实际上没有下转换构造函数,因此实际问题被掩盖了。

实际上,它是这样的:

class A() {}
class AA() : public A {}
class AAA() : public AA {}
class AAAA() : public AAA {}

这些类中的每一个都有一个定义,大致如下:

class AAAA() : public AAA {
    AAAA();
    virtual ~AAAA()
    // Downcasting constructor
    AAAA( const AAA &base ) : AAA(base) {};
}

然而,在类AAA()中,缺少AA的下转换构造函数,但编译器所能报告的只是找不到适用于AAAA(AAA)的构造函数。

事实上,链条断裂了,所以它无法达到AA或以上的水平(这正是我试图达到的)。

经验教训:在构建深度派生的对象链时,请始终仔细检查,以确保每个类都有下转换构造函数,并确保它是公共的。

在另一个不同类集的实例中,它被从结构转换为类,而Public:被遗忘了。在这种情况下,您不会收到无法访问的警告,只会收到强制转换失败。一切看起来都很好,但链条坏了。

也许这可以为遇到类似问题的其他人节省时间。