C ++:在函数中使用共享指针作为参数还是浪费内存?

时间:2017-12-02 15:12:26

标签: c++ function memory-management parameters shared-ptr

几周前我刚刚开始学习C ++,所以我不是内存管理方面的专家(在这种情况下这非常重要,但我还是没有理解我的头脑计算机体系结构以及指针如何存储信息)。这就是为什么我不确定将shared_ptr用作函数参数是否浪费内存。

我制作的是一个名为Usuario和Product的两个类的程序。第一个类代表User并有两个私有变量: std :: string m_name (它被称为的名称)和 float m_money (用户拥有的金额),以及各自的Getters和Setters。

第二个类代表产品并有三个私有变量: std :: string m_name (产品名称), float m_price (其价格),浮动 m_iva (一项名为Impuesto sobre el Valor Agregado的税,我设定为12%,所以 m_iva = m_price x 0.12 )和浮动 m_totalPrice (产品的最终价格,所以 m_totalPrice = m_price + m_iva ),他们各自的getter和两个与 m_name m_price 相关的setter。

使用各自的.h和.cpp文件设置这些类后,我使用std :: shared_pointer< class >在 main()函数中创建了对象。 objectName = std :: make_shared< class > ( parameters )并使用std :: shared_pointer< class >将它们作为参数传递给其他函数 aDiferentName 。例如,这是一个允许用户输入他的名字和金额的功能:

void SetCurrentUser(std::shared_ptr<Usuario> defaultUser) //Not sure if this is efficient.
{
    std::string userName;          //Variable to which the user input will be stored
    float money;                   //Variable to which the user input will be stored

    std::cout << "Input your name:  "; std::cin >> userName; defaultUser->SetName(userName);  //Sets a new name to defaultUser
    std::cout << "Input the amount of money you have:   "; std::cin >> money; defaultUser->SetMoney(money); //Sets a new amount of money to defaultUser

}

这是一个打印项目信息并告诉用户是否可以购买的功能。

    void PrintCurrentStatus(std::shared_ptr<Product> AnyProduct, std::shared_ptr<Usuario> User) //Not sure if this is efficient either
{ 
        std::cout << "\n" << std::setprecision(3) << AnyProduct->GetName() << " + " << AnyProduct->GetPrice() << "$" 
                  << " + " << AnyProduct->GetIVA() << " IVA = " << AnyProduct->GetTotal() 
                  << "$" << std::endl;            //Prints the product information like this: *line* *m_name* + *m_iva*IVA = *m_totalPrice*

        if ( User->GetMoney() >= AnyProduct->GetTotal() ) { //If the user's amount money is equal to or greater than the total price of the product. 
            std::cout << "User is allowed to pay.";
        }
        else { //If the user's amount of money is less than the total price of the product.
            std::cout << "User doesn't have enough money."; 
        }
    }

这是 main()函数,我在其中创建了所有对象(包括用户设置的&#34;&#34;和0作为初始参数):< / p>

int main()
{
    std::shared_ptr<Usuario> CurrentUser = std::make_shared<Usuario>(" ", 0);  //I created this object so that it can be set properly with the function SetCurrentUser
    SetCurrentUser(CurrentUser);   //Here the user sets it as they wish.
    std::shared_ptr<Product> Product1 = std::make_shared<Product>("Butter", 10.56, 10);    //Product1's name is Butter, costs 10.56 dollars and there are 10 units available
    std::shared_ptr<Product> Product2 = std::make_shared<Product>("Milk", 5.45, 10);   //Product2's name is "Milk", costs 5.45 dollars and there are 10 units of it available.
    PrintCurrentStatus(Product1, CurrentUser);  //Prints Product1's information and tells the user whether they can buy it or not.
    PrintCurrentStatus(Product2, CurrentUser); //Prints Product2's information and tells the user whether they can buy it or no.

    std::cin.ignore();       //We need to erase the contents of cin.
    std::cin.get();          //Waits until the user presses enter.
    return 0;                //The program ends here.
}

所有这些功能都位于同一个.cpp文件中。

所以,所有事情都说,程序的行为与我希望它的行为完全一致。但是,我确实想知道:我是否通过将std :: shared_ptr作为与主函数内创建的对象的共享指针对应的函数参数来浪费内存?有没有更有效的方法来获得相同的结果?

2 个答案:

答案 0 :(得分:1)

从技术上讲,你是“浪费内存”,因为std::shared_ptr包含两个内部指针(具有典型的C ++实现),因此将std::shared_ptr作为参数传递给函数实际上最终会通过两个指针;通过一个普通的指针参数,很明显,传递一个。

那又怎样?使用智能指针的好处超过了轻微的开销。

但是,你可以做得更好。在几乎所有用例中,您都可以通过引用传递参数,而不是:

void SetCurrentUser(const std::shared_ptr<Usuario> &defaultUser) 

对于典型的C ++实现,这最终会传递一个实际的指针,并且“浪费”与传递普通指针一样多的堆栈。您可以获得使用智能指针的所有好处,同时在堆栈上处理相同数量的宝贵字节。当然,按值和参考传递参数之间存在一些基本差异。但是几乎所有你现在正在编写的简单基本程序都没有功能上的区别,你的C ++书应该完全解释它们是什么,什么时候开始变得重要。

通常,可能会有一些额外的运行时开销,来自间接引用,但最有可能通过不必更新智能指针中保存的内部引用计数来节省几个CPU周期来抵消;并且,无论如何,在现代的多ghz平台上,除非使用原子钟或其他东西,否则它不会是任何人会注意到的。

答案 1 :(得分:0)

专家指南

Herb Sutter - C ++专家之一撰写了关于shared_ptr和其他智能指针的全文: https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/

这适用于您的问题:

  

指南:除非将智能指针作为函数参数传递   你想使用或操纵智能指针本身,如   分享或转让所有权。

TL; DR; shared_ptr的

长话短说 - shared_ptr存储的不仅仅是指针(引用计数,弱计数,删除函数),所以如果你不使用你的函数在课堂上存储shared_ptr somwhere那么指针是不必要的。通常,您正在“支付”您未使用的内容。你能在现实生活中做到这一点吗?

可以,可能会使性能变差。到什么程度?它必须要衡量。通常,在谈论性能时,我们不应在测量性能之前做出任何假设。

如何解决?

如果您不需要操作智能指针,则通过(可能是const)引用存储在shared_ptr中的类型,或者甚至按值传递。如果你需要传递可以为空的值,可能会通过原始指针传递(但我建议使用std::optionalboost::optional明确表示可选参数。

再次引用Herb Sutter:

  

指南:首选按值,*或&amp;而不是智能传递对象   指针。

所以我会改变这个:

void SetCurrentUser(std::shared_ptr<Usuario> defaultUser)

到此:

void SetCurrentUser(Usuario &defaultUser)

或者这个:

void SetCurrentUser(Usuario *defaultUser)

第一个逻辑上暗示该函数可能拥有智能指针的所有权,而其他人只表示它将使用Usuario类型的对象。