在构造函数中反序列化 const 成员对象

Posted

技术标签:

【中文标题】在构造函数中反序列化 const 成员对象【英文标题】:Deserialize a const member object in a constructor 【发布时间】:2021-05-31 19:26:21 【问题描述】:

我需要在构造函数中初始化类的 const 成员对象,但成员的构造函数只创建一个空对象,而真正的初始化必须通过从文件中反序列化该对象来完成。成员对象的类不是我的,我不能改变它。也就是说,它是一个 Dlib 模型,下面的代码模拟了它的行为:

#include <iostream>
#include <string>

// not my class, can't be changed
class ShapePredictor 

    friend std::istream& operator >> (std::istream& stream, ShapePredictor&);

public:
    ShapePredictor() = default;
    ShapePredictor(const ShapePredictor& other) : data(other.data)  std::cout << "copy" << std::endl; 
    ShapePredictor(ShapePredictor&& other) : data(std::move(other.data))  std::cout << "moved" << std::endl; 
private:
    std::string data;
;

// deserialization 
std::istream& operator >> (std::istream& stream, ShapePredictor& sp)

    sp.data = "test33";
    return stream;


class FaceExtractor

public:
    FaceExtractor()
    
        std::cin >> this->sp;       // won't compile        
    

private:
    const ShapePredictor sp;
;

int main(int argc, char* argv[])

    FaceExtractor extractor;
    return 0;

我不确定最好的方法是什么。首先想到的是使用const_cast&lt;&gt;()

class FaceExtractor

public:
    FaceExtractor()
    
        std::cin >> const_cast<ShapePredictor&>(this->sp);
    

private:
    const ShapePredictor sp;
;

它有效,但使用const_cast&lt;&gt;() 通常被认为是一种不好的做法。我读到它主要是为了与不正确的旧 API 兼容而设计的。我不太确定在我的情况下是否可以使用它。

解决它的另一种方法是创建一个成员函数deserialize(),它将类加载到一个临时对象中并返回它:

class FaceExtractor

public:
    FaceExtractor()
        : sp(deserialize())
       

    ShapePredictor deserialize()
    
        ShapePredictor tmp;
        std::cin >> tmp;
        return tmp;
    ;

private:
    const ShapePredictor sp;
;

这涉及创建一个临时的,这是不可取的。希望 NRVO 会省略一份副本,但在 MSVC 中,它仍然需要额外的一步。

我想知道初始化此类对象的常见做法是什么?

【问题讨论】:

只要将成员变量设为非const即可。拥有const 成员变量通常很痛苦,而且很少有用。 @TedLyngmo 我不希望它在构建后被修改。 没关系,但它是private,所以任何东西都无法从课堂外修改它。 @TedLyngmo 好吧,我不希望它(无意中)被这个类的方法修改 @TedLyngmo 是的,我刚刚接受了你的回答。谢谢。 【参考方案1】:

只需将成员变量设为非const。拥有const 成员变量通常很痛苦,而且很少有用。

如果您绝对必须拥有它 const,您可以创建一个继承自 ShapePredictor 的类并添加一个执行流式传输的构造函数。

struct ShapePredictorStreamable : public ShapePredictor 
    ShapePredictorStreamable(std::istream& is) 
        is >> *this;
    
;

class FaceExtractor 
public:
    FaceExtractor() : sp(std::cin) 

private:
    const ShapePredictorStreamable sp;
;

【讨论】:

以上是关于在构造函数中反序列化 const 成员对象的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中反序列化复杂对象

在javascript中反序列化json对象

在 symfony 中反序列化对象返回异常 [关闭]

C# 在单个对象中反序列化两个 Jarray 对象

将对象序列化为 XElement 并在内存中反序列化

如何在 C# 中反序列化多个 JSON 对象?