【问题标题】:C++ Ways to pass a pointer to a temporary object (on the heap) to a function?C ++将指向临时对象(在堆上)的指针传递给函数的方法?
【发布时间】:2011-08-09 09:01:30
【问题描述】:

我有一个函数,它接受一个指向自定义类对象的指针(实际上是指向一个基类的指针,这样多态性才起作用)。然而,在调用例程中,此对象专门用于此调用的目的,即是临时的。比如这样:

class A { /** stuff */ };
class B : public A { /** stuff */ };

void doSomething( const A* const _p ) { /** stuff */ }

void callingRoutine()
{
  A* tempPointer = new B;
  doSomething( tempPointer );
  delete tempPointer;
}

现在,由于在对doSomething 的调用中我真的只需要B 类型的对象,有没有办法在一行中做到这一点?正在做

doSomething( new B );

造成内存泄漏(valgrind 这么说)。或者会

doSomething( &B );

是推荐的方式吗?后者可以编译,但会发出有关将指针传递给临时对象的警告。这是我想做的,但是这样安全吗?

【问题讨论】:

  • 如果您只想在 doSomething 的范围内使用它,为什么还要在其范围之外创建对象?

标签: c++ argument-passing


【解决方案1】:

如果可以更改被调用函数的签名,请将其更改为:

void doSomething( A const& obj );

然后你可以调用它:

doSomething( B() );

如果不能,应该声明一个局部变量:

void callingRoutine()
{
    B temp;
    doSomething( &temp );
}

如果调用函数比较长,如果temp是有问题的 不会立即销毁,您可以将其附加在 {...} 中:

void callingRoutine()
{
    {
        B temp;
        doSomething( &temp );
    }
    //  More code here...
}

不过,一般来说,如果有必要,您的功能是 可能太长了。

【讨论】:

    【解决方案2】:

    最干净的方法是这样做

    B b;
    doSomething(&b);
    

    但是你真正应该写什么取决于doSomething 函数的作用。如果可以在callingRoutine 的末尾销毁b,那么这是更快更干净的方法,因为在堆栈上分配比new 更快,并且不需要您在之后删除b

    【讨论】:

    • 有时两行优于一行:-)
    • 两行就可以了。然后是 iammilind 的解决方法;-)
    【解决方案3】:

    在您的情况下,您可以使用自动变量(在堆栈上)

    void callingRoutine()
    {
      B obj;
      doSomething( &obj );
    }  // obj is destroyed automatically
    

    这不会发出警告。此外,只有当您确实想要在函数范围之外更长时间地引用/访问内存地址时,才应该使用new。在功能块中,使用new 分配是没有意义的。

    请参考 Bjarne 页面上的 this link,他在其中指出了与您完全相同的示例。

    顺便说一句,如果您只想要一条线,那么解决方案将不干净,但这里有一个解决方法:

    B obj; doSomething( &obj );
    

    【讨论】:

    • “单行”请求的好解决方法;-) 两行也可以,我只是想知道在这种情况下“推荐”的方式是什么..
    • @janitor048,推荐的方式将是答案的第一部分。您也可以参考链接了解更多信息。
    • 只是一个注释,但如果你是在一个更大的函数的上下文中执行此操作,可能值得将B obj; doSomething( &obj ); 放入{...},以便obj 尽快被破坏尽可能。
    • @James,是的。事实上,我会把B obj; 放在doSomething() 中;如果在调用该方法后我真的不需要它。 :)
    【解决方案4】:

    我有点惊讶没有人指出明显的:

    void callingRoutine()
    {
        doSomething(&B());
    }
    

    我想知道需要传递指向对象的指针的整体设计,但是当它完成后,你显然会忽略它所操作的对象,但如果你确定你想要什么以及你想要的其余部分'正在做,这似乎是实现它的最简单、最直接的方法。

    【讨论】:

    • 这是我在提问时想到的可能性之一,我在原始帖子中也提到了它(实际上我写了doSomething(&B)而不是doSomething(&B()),但我的构造函数无论如何都会接受参数,因此它将是&B(x,y,z))。至于一般概念:我需要用一个接口注册不同的数据集合,用于存储/立即输出/稍后输出。至少在立即输出的情况下,临时数据收集就足够了。并且需要指针来使用虚函数..
    【解决方案5】:

    也许像下面这样?

    void doSomething( std::auto_ptr<A> _p ) { /** stuff */ }
    
    void callingRoutine()
    {
      doSomething(std::auto_ptr<A>(new B));
    }
    

    【讨论】:

    • 是的,这与我的想法一致。谢谢。但可能其他人是对的,在这种特定情况下,两行和堆栈上的一个临时对象是最简单的解决方案..
    • @janitor048,当然,我的目标是指出它可以做到——但这并不是真正的惯用方式......
    • 当然,我意识到这一点。感谢您的建议,因为它可能在其他情况下派上用场。
    • doSomething(std::auto_ptr&lt;A&gt;(new B).get());以免改变函数签名?
    【解决方案6】:

    解决问题的最简单方法是按如下方式更改代码:

    void callingRoutine()
    {
        B temp;
        doSomething( &temp );
    }
    

    这是可行的,因为您只需要在 doSomething() 中进行多态访问,并且通过获取它的地址来传递指向 temp 的指针这一事实可以保证这一点。

    【讨论】:

      【解决方案7】:

      传递一个指向临时对象的指针通常是个坏主意,因为该对象可能在被调用者完成使用它之前就被销毁。在您的示例中,doSomething() 应该在对象被删除或超出范围之前返回,因此,直到doSomething 不存储对该对象的任何引用,这都不是问题。

      【讨论】:

        【解决方案8】:

        您可以在调用或表达式期间将临时值(r 值)转换为左值:

        template<class T>
        inline T& l_value(T const& t)
        {
            return const_cast<T&>(t);
        }
        
        struct A {};
        
        void doSomething(const A*);
        
        void foo()
        {
            doSomething(&l_value(A()));
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-03-31
          • 1970-01-01
          • 1970-01-01
          • 2017-08-09
          • 2018-09-03
          • 1970-01-01
          • 2013-04-14
          相关资源
          最近更新 更多