【问题标题】:Creating a new object and passing in method parameter [closed]创建一个新对象并传入方法参数
【发布时间】:2016-08-26 15:39:28
【问题描述】:

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

wrapper.set_state( new Medium() );

在 C++ 中与 this 等价的是什么? 我想我可以先创建对象然后传递它,但是能够在参数中创建它看起来更整洁。

【问题讨论】:

  • 在c++中wrapper.set_state(Medium() );没有错。
  • 仅仅因为它在语法上有效并不意味着它是正确的做事方式。 C++ 不是 Java。它使用自己的习语。
  • 这是一种方式。您也可以按值或常量引用传递。正确的解决方案取决于上下文。
  • 如果您的包装器拥有介质,而单个介质仅由一个包装器拥有,则只需通过调用 std::unique_ptr 传递 wrapper.set_state( std::make_unique<Medium>() ); 标准库提供了出色的智能指针。
  • 为了得到一个好的答案,你需要提供更多的上下文。对象是被传递对象的唯一所有者吗,它可以只是一个普通的成员变量吗?

标签: c++ oop methods parameters instantiation


【解决方案1】:

在 Java 中

wrapper.set_state( new Medium() );

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

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

void set_state(Medium* medium);

但是你要做的是将一个非引用计数指针传递给一个新的 Medium 实例。您将负责确保它稍后是deleted。如果所有 set_state 都是这样:

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

每次调用 set_state 时都会引入内存泄漏。在 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;
}

【讨论】:

  • @user2079303 已添加,请参阅编辑后的答案。
  • @kfsone 不是所有对象都通过引用传递吗?使用“Const”究竟会实现什么?对象会在某个时候被自动删除吗?如果是,什么时候?
  • @kfsone 很好的补充。
  • @MartinRand 为什么你会认为所有对象都通过引用传递?无论如何,我建议您学习您使用的语言:stackoverflow.com/questions/388242/…
  • @kfsone 但是如果 const 向调用者承诺你不会修改对象,那为什么不直接传值呢?
【解决方案2】:

C++ 中的 this 等价于什么?

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

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

wrapper.set_state(Medium());

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

【讨论】:

    【解决方案3】:

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

    #include <iostream>
    #include <memory> // c++11
    
    class Helper {
    public:
        Helper () { std::cout << "Helper says hi\n"; }
        void Speak() { std::cout << "Helper says bark\n"; }
        ~Helper () { std::cout << "Helper says bye\n"; }
    };
    
    class Message {
    public:
        Message (Helper* h, bool freeme = false) {
            std::cout << "Message says hi..btw you have a memory leak\n";
            h->Speak();
            if (freeme) {
                std::cout << "Message says nice one\n";
                delete h;
            }
        }
        Message (std::unique_ptr<Helper> h) {
            std::cout << "Message say hi\n";
            h->Speak();
        }
        ~Message () {
            std::cout << "Message says bye\n";
        }
    };
    
    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;
    }
    

    【讨论】:

      【解决方案4】:

      这取决于参数的类型,考虑以下几点:

      • 值参数:void set_state(Medium) 使用临时移动初始化它,即使用set_state(Medium())
      • 右值引用参数:void set_state(Medium&amp;&amp;),绑定它来引用一个新构造的临时,即使用set_state(Medium())(这与值参数大小写的语法相同,但语义略有不同)
      • 左值引用参数:void set_state(Medium&amp;),传递给它一个新分配对象的引用,即使用set_state(*new Medium())
      • 指针参数:void set_state(Medium*),传递一个指向新分配对象的指针,即使用set_state(new Medium())

      如果参数类型具有任何 constvolatatile 修饰符,以及使用非歧义基类型 Medium 声明的参数,这同样适用


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

      另一个注意事项,因为 C++ 与 Java 非常不同(在语义方面),我建议阅读一本关于该语言的好书或其他一些资源,而不是就你不理解的所有事情提出问题,因为你可能会错过以这种方式存在一些重要差异并产生灾难性的后果。

      【讨论】:

      • 请不要以*new Medium()为例。这几乎肯定会泄漏内存,而且肯定不合适。
      猜你喜欢
      • 2021-12-26
      • 2019-03-22
      • 1970-01-01
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      相关资源
      最近更新 更多