6

In Java we can create and pass a new object to a method within its parameters like so:

wrapper.set_state( new Medium() );

What is the equivalent to this in C++? I suppose I could create the object before and then pass it, but being able to create it in the parameter would seem neater.

M-R
  • 411
  • 2
  • 6
  • 15

4 Answers4

7

In Java

wrapper.set_state( new Medium() );

creates a new, reference counted, instance of Medium and passes it by reference to wrapper's set_state function.

In C++ the above code is technically valid, in your wrapper class set_state would be defined as:

void set_state(Medium* medium);

But what you would be doing is passing a non-reference counted pointer to a new instance of Medium. You would be responsible for ensuring that it is deleted later. If all set_state did was this:

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

you would be introducing a memory leak every time you made a second call to set_state. In C++, when you overwrite a raw pointer like this, there is no reference counting. If nobody is pointing to the allocation any more, the allocation is lost/leaked.

You might prefer to pass an object by reference:

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

invoked via:

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

// or

wrapper.set_state(Medium());

or you can pass by value:

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

// invocation:

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

Although this is a copy, in some cases the compiler is able to elide out one of the copies (see http://ideone.com/gNICYt)

If you absolutely need to use a pointer (several things will reference the exact same Medium instance) you might want to consider using std::shared_ptr which provides reference counting.

#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;
}
kfsone
  • 23,617
  • 2
  • 42
  • 74
  • @user2079303 added, see edited answer. – kfsone May 01 '16 at 23:52
  • @kfsone Aren't all objects passed by reference anyway? What exactly would using "Const" achieve? Would the object be automatically deleted at some point, and if so, when? – M-R May 02 '16 at 00:04
  • @kfsone good addition. – eerorika May 02 '16 at 00:06
  • @MartinRand why would you think that *all objects passed by reference anyway*? In any case, I recommend studying the language that you use: http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – eerorika May 02 '16 at 00:07
  • @kfsone, yeah don't know what I was thinking. Had a brain-fart. Sorry. So is "Const' a temporary reference? How would I delete the object? – M-R May 02 '16 at 00:09
  • In C++ the only automatic-lifetime variables are local variables, which are concrete instances of an object/primitive, e.g. `int i`, stored on the stack. When the end of the scope is reached, the object is destroyed as the stack rolls back. `const` is a contractual modifier, it promises the caller that you won't modify the object. You could remove the keyword and the code would work the same up until you reach a more advanced stage and have a `const` instance of an object, at which point it won't be able to call the non-const version of set_state. wouldn't worry about `const` too much, for now – kfsone May 02 '16 at 00:49
  • @MartinRand Sorry, forgot to tag you in the above reply. – kfsone May 02 '16 at 00:49
  • 1
    @kfsone But if const promises the caller that you won't modify the object, then why not just pass by value? – M-R May 02 '16 at 00:58
  • For a large object, pass-by-value can incur an additional copy. If you pass-by-reference it can copy directly from the source object. – kfsone May 02 '16 at 00:59
  • About the "pass by value" example: Can I also invoke via `wrapper.set_state(Medium());`? I expect that a temporary `Medium()` will be created and copied. The copy gets passed to the function? – LCsa Aug 04 '18 at 12:26
2

What is the equivalent to this in C++?

There are multiple similar ways to the implement the quoted Java statement in c++. The exactly same syntax happens to actually be valid c++ assuming the function is expecting a pointer. Whether it is desirable to pass to the function, a raw pointer to a manually allocated object, is something that you must consider. It most likely is not desirable.

The simplest way to create a new object in c++, is to create a temporary. The analogous syntax for creating a temporary and passing it to a function would be:

wrapper.set_state(Medium());

Because Java references are counted, the semantically closest analogue would (probably arguably) be to pass a std::shared_ptr<Medium>. But, because in c++ unlike in Java, you have the option of value semantics but on the other hand, you don't have garbage collection, you cannot assume that you actually should have the same semantics.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I can be sure this is the answer the OP was looking for. Just a simple way to construct and pass objects to functions – Jagat Jan 18 '23 at 22:26
0

Equivalent yes, but maybe not same results:

#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;
}
Joel
  • 1,805
  • 1
  • 22
  • 22
-1

It depends on the type of the parameter, consider the following:

  • Value parameter: void set_state(Medium) move-initialise it with a temporary, i.e. use set_state(Medium())
  • Rvalue-reference parameter: void set_state(Medium&&), bind it to refer to a newly constructed temporary, i.e. use set_state(Medium()) (this is the same syntax as the value parameter case, but the semantics are slightly different)
  • Lvalue-reference parameter: void set_state(Medium&), pass it a reference to a newly allocated object, i.e. use set_state(*new Medium())
  • Pointer parameter: void set_state(Medium*), pass it a pointer to a newly allocated object, i.e. use set_state(new Medium())

The same applies if the parameter type has any const or volatatile modifiers, as well as if the parameter is declared with a type that is a non-ambigiouse base type of Medium


Note: be careful when using new, unlike Java, C++ does not require automatic garbage collection, so you will want to make sure the object is deleted when it is no longer needed and not before. (the safest thing would be to just not delete your objects, but this will just waste memory)

Another note, as C++ is very different from Java (in semantics terms) I suggest reading a good book or some other resource about the language as opposed to asking questions about everything thing you don't understand, as you will likely miss some important differences this way and have disastrous results.

Isaac
  • 816
  • 5
  • 12
  • Please don't use `*new Medium()` as an example. That's almost guaranteed to leak memory and most certainly not appropriate. – eerorika May 01 '16 at 23:38