创建一个新对象并传入方法参数

Creating a new object and passing in method parameter

本文关键字:方法 参数 对象 新对象 一个 创建      更新时间:2023-10-16

在Java中,我们可以创建一个新对象,并在其参数范围内将其传递给方法,如下所示:

wrapper.set_state( new Medium() );

在C++中与此等价的是什么?我想我可以在之前创建对象,然后传递它,但能够在参数中创建它似乎会更整洁。

在Java 中

wrapper.set_state( new Medium() );

创建一个新的、引用计数的Medium实例,并通过引用将其传递给包装器的set_state函数。

在C++中,上述代码在技术上是有效的,在包装类中,set_state将被定义为:

void set_state(Medium* medium);

但您要做的是将一个非引用计数指针传递给Medium的新实例。您将负责确保在第1天之后是CCD_。如果所有的set_state都是这样的:

void set_state(Medium* medium)
{
    this->medium = medium;
}

每次对setstate进行第二次调用时,都会引入内存泄漏。在C++中,当覆盖像这样的原始指针时,没有引用计数。如果没有人再指向分配,则分配将丢失/泄漏。

您可能更喜欢通过引用传递对象:

void set_state(const Medium& medium)
{
    this->medium = medium;  // copy
}

通过:调用

Medium m;
// populate m
wrapper.set_state(m);
// or
wrapper.set_state(Medium());

或者您可以通过值传递:

void set_state(Medium medium)
{
    this->medium = medium;  // copy
}
// invocation:
Medium m;
// populate m
wrapper.set_state(m);  // copy

尽管这是一个副本,但在某些情况下,编译器能够消除其中一个副本(请参阅http://ideone.com/gNICYt)

如果你绝对需要使用指针(有几个东西会引用完全相同的Medium实例),你可能需要考虑使用std::shared_ptr,它提供了引用计数。

#include <memory>
struct Medium {};
class Wrapper {
    std::shared_ptr<Medium> medium;
public:
    void set_state(std::shared_ptr<Medium> medium) {
        this->medium = medium;  // if we'd called it m_medium, or medium_
        // we could just have written
        // m_medium = medium; or medium_ = medium;
    }
};
int main(void) {
    Wrapper w;
    w.set_state(std::make_shared<Medium>());
    return 0;
}

在C++中与此等价的是什么?

有多种类似的方法可以在c++中实现引用的Java语句。假设函数需要一个指针,那么完全相同的语法恰好是有效的c++。您必须考虑是否需要将指向手动分配对象的原始指针传递给函数。这很可能是不可取。

在c++中创建新对象的最简单方法是创建一个临时对象。创建临时并将其传递给函数的类似语法是:

wrapper.set_state(Medium());

因为Java引用是被计算在内的,所以语义上最接近的类似方法(可能可以说)是传递std::shared_ptr<Medium>。但是,因为在c++中,与Java不同,您可以选择值语义,但另一方面,您没有垃圾收集,所以您不能假设您实际上应该具有相同的语义。

等价的是,但可能不相同的结果:

#include <iostream>
#include <memory> // c++11
class Helper {
public:
    Helper () { std::cout << "Helper says hin"; }
    void Speak() { std::cout << "Helper says barkn"; }
    ~Helper () { std::cout << "Helper says byen"; }
};
class Message {
public:
    Message (Helper* h, bool freeme = false) {
        std::cout << "Message says hi..btw you have a memory leakn";
        h->Speak();
        if (freeme) {
            std::cout << "Message says nice onen";
            delete h;
        }
    }
    Message (std::unique_ptr<Helper> h) {
        std::cout << "Message say hin";
        h->Speak();
    }
    ~Message () {
        std::cout << "Message says byen";
    }
};
int main()
{
    { Message msg1(new Helper); } // warning: leak
    std::cout << "--- 1 ---n";
    { Message msg2(std::unique_ptr<Helper>(new Helper));}
    std::cout << "--- 2 ---n";
    { Message msg3(new Helper); } // warning: leak
    std::cout << "--- 3 ---n";
    { Message msg3(new Helper, true); }
    return 0;
}

这取决于参数的类型,请考虑以下内容:

  • 值参数:void set_state(Medium) move用临时初始化,即使用set_state(Medium())
  • Rvalue引用参数:void set_state(Medium&&),绑定它引用一个新建的临时,即使用set_state(Medium())(这与value参数的情况语法相同,但语义略有不同)
  • Lvalue引用参数:void set_state(Medium&),将对新分配对象的引用传递给它,即使用set_state(*new Medium())
  • 指针参数:delete0,向它传递一个指向新分配对象的指针,即使用set_state(new Medium())

如果参数类型具有任何constvolatatile修饰符,以及如果参数是用Medium 的非模糊基类型声明的,则同样适用


注意:使用new时要小心,与Java不同,C++不需要自动垃圾收集,因此您需要确保在不再需要对象时而不是以前删除该对象。(最安全的方法是不delete您的对象,但这只会浪费内存)

另一点需要注意的是,由于C++与Java(在语义方面)非常不同,我建议阅读一本关于该语言的好书或其他资源,而不是对你不理解的一切提出问题,因为这样你可能会错过一些重要的差异,并产生灾难性的结果。