Domanda

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?

È stato utile?

Soluzione

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top