使用 std::vector 和 shared_ptr 优化 C++ 代码

超级捕食者

我们的老师正在教我们一些优化技巧,为此她给了我们以下 C++ 代码来优化。

struct IStruct
{
    virtual bool GetType() const = 0;
};

struct FStructA : public IStruct
{
    std::string Key;
    int IntData;

    virtual bool GetType() const override
    {
        return true;
    }
};

struct FStructB : public IStruct
{
    std::string Key;
    float FloatData;

    virtual bool GetType() const override
    {
        return false;
    }
};

class SomeSystem
{

public:
    void Add(const FStructA& Struct)
    {
        //DataElements.push_back(std::shared_ptr<IStruct>(new FStructA(Struct)));
        DataElements.emplace_back(std::shared_ptr<IStruct>(new FStructA(Struct)));
    }

    void Add(const FStructB& Struct)
    {
        //DataElements.push_back(std::shared_ptr<IStruct>(new FStructB(Struct)));
        DataElements.emplace_back(std::shared_ptr<IStruct>(new FStructB(Struct)));
    }

    void Process()
    {
        for (std::shared_ptr<IStruct> DataElement : DataElements)
        {
            if (DataElement->GetType())
            {
                FStructA StructA = *static_cast<FStructA*>(DataElement.Get());
                // Process A
            }
            else
            {
                FStructB StructB = *static_cast<FStructB*>(DataElement.Get());
                // Process B
            }
        }
    }

private:
    std::vector<std::shared_ptr<IStruct>> DataElements;
};

现在,如您所见,我已经优化了一行,而不是push_back使用emplace_back. 这肯定会节省一些内存并提高速度,但不会那么多。我认为这不是这个问题的答案。肯定还有其他我想念的东西。

另一点是重载的Add功能,我想优化它,但我认为它正确地完成了它的工作。

因此我很困惑,我还能在哪里优化?

雷米勒博

FStructAFStructB共享一个公共成员Key,因此可以考虑将其移动到它们都派生自的基类。

在处理多态类型时,基类几乎总是需要一个virtual析构函数,以便在通过基类指针销毁对象时正确调用派生构造函数。这在使用智能指针时尤其重要,例如在多态对象的容器中,正如这段代码所做的那样。

struct成员是public默认的,并且默认情况下使用继承struct从另一个派生,因此显式声明继承自是多余的。structpublicFStructAFStructBpublicIStruct

使用时override,无需virtual再次指定override暗示virtual其本质。

避免new与智能指针构造函数一起使用。改用std::make_...()函数 - std::make_unique()forstd::unique_ptrstd::make_shared()for std::shared_ptr()

重载的Add()方法可以合并为一个模板方法。

emplace_back()push_back()处理(智能)指针时相同,尤其是处理必须在容器外部构造的多态类型时。仅当容器本身能够直接构造元素时,使用emplace_back()而不是push_back()有意义,然后您只需提供emplace_back()构造函数参数。但在这段代码中情况并非如此。

在您的range-for循环中,您正在DataElement 按 value 获取,这将制作每个shared_ptrin的副本DataElements,从而在它们进入和离开作用域时递增和递减它们的引用计数。虽然这很好,但这是不必要的开销。你应该DataElement参考参考。事实上,在迭代任何容器时,您通常应该使用引用,除非您确实需要副本,或者制作副本的开销可以忽略不计(即,使用平凡类型)。

auto在声明变量时,尤其是在处理模板类型时,请尽可能考虑使用这在range-for循环中特别有用

不要static_cast与 a 的原始指针一起shared_ptr使用,static_pointer_cast而是使用来维护正确的共享所有权语义。

不要不必要地复制对象。您正在取消引用 的结果static_cast,然后制作对象的副本,然后您正在处理副本,而不是原始对象。这有时很有用,但此代码不是其中之一。使用指针或引用来避免复制。

除非确实需要,否则不要将基类强制转换为派生类。如果您有多态类型(如此代码所做的那样),请尽可能使用多态行为(即虚拟方法)。正确的多态处理逻辑不应该关心它在操作什么类型。

不要使用std::shared_ptr什么时候std::unique_ptr就足够了。std::shared_ptr有没有的开销(引用计数、控制块等)std::unique_ptr共享所有权有其用途,但此代码并未展示它们。

话虽如此,请尝试更像这样的事情:

struct IStruct
{
    std::string Key;
    virtual ~IStruct() = default;
    //virtual bool GetType() const = 0;
    virtual void Process() = 0;
};

struct FStructA : IStruct
{
    int IntData;

    /*
    bool GetType() const override
    {
        return true;
    }
    */

    void Process() override
    {
        // Process A
    }
};

struct FStructB : IStruct
{
    float FloatData;

    /*
    bool GetType() const override
    {
        return false;
    }
    */

    void Process() override
    {
        // Process B
    }
};

class SomeSystem
{
public:
    template<typename T, typename... Args>
    void Add(Args&&... args)
    {
        DataElements.push_back(/*std::make_shared*/std::make_unique<T>(std::forward<Args>(args)...));
    }

    void Process()
    {
        for (auto &DataElement : DataElements)
        {
            /*
            if (DataElement->GetType())
            {
                auto StructA = static_pointer_cast<FStructA>(DataElement);
                // Process A
            }
            else
            {
                auto StructB = static_pointer_cast<FStructB>(DataElement);
                // Process B
            }
            */

            DataElement->Process();
        }
    }

private:
    std::vector</*std::shared_ptr*/std::unique_ptr<IStruct>> DataElements;
};

int main()
{
    SomeSystem system;
    system.Add<FStructA>(...params as needed...);
    system.Add<FStructB>(...params as needed...);
    system.Process();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

C ++ std :: shared_ptr参考的reinterpret_cast优化

如何正确使用 std::shared_ptr 和 std::map

使用boost :: shared_ptr <std :: list <T >>初始化boost :: shared_ptr <std :: vector <T >>

使用std map和shared_ptr的奇怪内存行为

C ++使用指向std :: shared_ptr的Raw指针

在C ++中,空std :: shared_ptr和空std :: shared_ptr有什么区别?

使用std :: weak_ptr和std :: shared_ptr进行阴影

使用C ++ std :: unique_ptr <>或std :: shared_ptr <>来管理Objective-C对象

使用std :: vector <std :: shared_ptr <const T>>是反模式吗?

使用std :: move与std :: shared_ptr

在基于范围的for循环中使用shared_ptr到std :: vector

std :: shared_ptr和继承

使用std :: shared_ptr和std :: thread的编译器错误

在C ++中创建vector的shared_ptr

了解C ++ std :: shared_ptr

使用shared_ptr启动std :: thread

使用* this作为std :: shared_ptr

使用相同的函数但具有不同的重载来转换std :: tr1 :: shared_ptr <T>和std :: shared_ptr <T>

如何使用std :: shared_ptr <void>和另一种类型的std :: shared_ptr进行函数重载?

传递std :: shared_ptr的std :: vector,而不更新对象

在C ++中将unique_ptr和shared_ptr与函数参数一起使用

通过 std::shared_ptr 使用 Rcpp 和 RcppParallel 的线程安全函数指针

C ++设置和shared_ptr

C ++ 11 shared_ptr和pthread

与临时对象一起使用时了解C ++ std :: shared_ptr

C ++ std :: shared_ptr,是否operator =重载以使用复制构造函数?

使用std :: shared_ptr作为Objective-C中的全局变量

我对std :: vector <shared_ptr>有疑问

替换std :: vector中的shared_ptr元素