2

Background

I am writing a driver for a networkprotocol and have a function write(std::shared_ptr<package> package), where package is std::array<buffer_ptr,2> (0=>header, 1=> body). For convenience I want to write a function write(buffer_ptr body), that autogenerates the header and calls the first form of write. To do so I want to us std::make_shared, however I have issues initializing the std::array from the make_shared call.

Code

typedef std::shared_ptr<std::vector<uint8_t>> buffer_ptr;
typedef std::array<buffer_ptr, 2> package_t;
typedef std::shared_ptr<package_t> package_ptr;

void connection::write(package_ptr package) {
    ... //do stuff
}

void connection::write(buffer_ptr body) {
    buffer_ptr header = buildHeader(body);
    write(std::make_shared<package_t>(???)) //here I want to initialize the array with {header,body}
}

What I tried for ???

(these led to compiler errors)

{header, body}
{{header, body}}
std::initializer_list<buffer_ptr>{header, body}

Question:

  1. Is there a solution to make this work or do I have to write something like:

    package_ptr package=new package{header, body}; write(package);

    1.b) Do I loose efficency by having to resort to package_ptr(new package)? (I remember make shared allocating memory for the pointer and the instance in one chunk, to save memory requests)

  2. On Cppreference is reads:

    Moreover, f(shared_ptr(new int(42)), g()) can lead to memory leak if g throws an exception. This problem doesn't exist if make_shared is used.

    Why would memory be leaked (could int(42) be constructed before g is called, and g be called before shared_ptr is called)? And would the alternative code from 1. suffer from such a potential leak?

ted
  • 4,791
  • 5
  • 38
  • 84
  • 2
    `write(std::make_shared( package_t{header, body} ));` – Cubbi Apr 01 '14 at 20:03
  • @Cubbi Nice! microsoft compiler didn't like it though :( – a.lasram Apr 01 '14 at 20:13
  • @Cubbi: what happens if `make_shared` throws(i.e. out of memory)? WIll the already constructed `package_t` be leaked? – ted Apr 01 '14 at 20:33
  • @ted no, it will call the destructors of its two members. – Cubbi Apr 01 '14 at 21:56
  • @Cubbi what will call the destructor of its two members? `package_t`? Would you mind pointing me to the difference to the example in 2.) in the question where this apparently does not work according to cpp reference? – ted Apr 01 '14 at 22:54

1 Answers1

1

First:

array doesn't explicitly declare a constructor. In particular, it doesn't have a constructor that takes a initializer list.

I think a clean way is to avoid the explicit new in the code and leave it to standard functions:

package_t p = {header, body};
write(std::make_shared<package_t>(p));

The code would have looked even better if there was neither new nor std::shared_ptr :

package_t p = {header, body};
write(p);

Second, on Cppreference.com it reads:

Moreover, f(shared_ptr(new int(42)), g()) can lead to memory leak if g throws an exception. This problem doesn't exist if make_shared is used.

The standard doesn't specify an order for evaluating function arguments and expressions can be evaluated in any order as long as they produce the same result.

In

f(shared_ptr(new int(42)), g())

new int(42) has to precede shared_ptr() but not g() and this can cause a leak if g throws.

In

f(make_shared<int>(42), g())

the allocation happens inside make_shared. If g is called before make_shared and if it throws, the memory would never get allocated.

If make_shared is called before g and if g throws, the shared_ptr object would have been created already and it's destruction is guaranteed because of RAII

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
a.lasram
  • 4,371
  • 1
  • 16
  • 24
  • the `shared_pointer` has to stay, because it goes through an async write and the pointer is used to release the header/body after the write calls the callback – ted Apr 01 '14 at 20:16