1

If you run the code below fread will return with 0. If you change p to use buf instead of the unique_ptr it will work. Why? I ran this in MSVC 2013

#include <iostream>
#include <map>
#include <memory>
using namespace std;

int main(int argc, char *argv[]) {
    char buf[1024 * 32];
    auto buf2 = make_unique<char>(1024 * 32);

    {
        memset(buf, 0, sizeof buf);
        FILE *f = fopen("tmpfile", "wb");
        printf("write = %d\n", fwrite(buf, 1, sizeof buf, f));
        fclose(f);
    }

    //char*p = 0 ? buf2.get() : buf;
    //char*p = buf;
    char*p = buf2.get();

    FILE *f = fopen("tmpfile", "r+b");

    printf("read = %d\n", fread(p, 1, sizeof buf, f));

    fclose(f);
    return 0;
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 3
    your `buf2` is holding a single character – Piotr Skotnicki Nov 05 '14 at 19:07
  • @PiotrS.: Is it? How do I allocate an array? and I can't believe I'm not getting warnings –  Nov 05 '14 at 19:07
  • `auto buf2 = unique_ptr(new char[1024 * 32]);` – Piotr Skotnicki Nov 05 '14 at 19:09
  • 1
    `make_unique(1024 * 32)` is complete nonsense. –  Nov 05 '14 at 19:11
  • 7
    Or `auto buf2 = make_unique(1024 * 32);` – Praetorian Nov 05 '14 at 19:11
  • @PiotrS. that one line gives me a dozen compile errors. `unique_ptr buf2(new char[1024 * 32]);` seems to work. I'll accept it as an answer –  Nov 05 '14 at 19:11
  • @DieterLücking: It appears this compiler doesn't warn me of this nonsense! –  Nov 05 '14 at 19:11
  • 5
    @acidzombie24 `unique_ptr buf2(new char[1024 * 32]);` is not valid, as it does not use `delete[]` operator for freeing the memory – Piotr Skotnicki Nov 05 '14 at 19:14
  • @Praetorian/Dieter: I'm a little surprise `char[]` works. That makes me think its a pointer to a pointer –  Nov 05 '14 at 19:14
  • 1
    @acidzombie24: Why that? It's an explicit overload for arrays of unkown length. – Deduplicator Nov 05 '14 at 19:15
  • I don't see how pointer to pointer comes into the picture. `unique_ptr` has a partial specialization for `T[]` that handles allocation/deallocation using `new[]/delete[]`. That's what you're using when you call `make_unique(...)` – Praetorian Nov 05 '14 at 19:16
  • compare: http://coliru.stacked-crooked.com/a/dae2a6f2427468a9 – Piotr Skotnicki Nov 05 '14 at 19:17
  • @Praetorian Do you want to actually write an answer so I can upvote that instead of your comments? – Barry Nov 05 '14 at 19:18
  • @Barry I'm waiting to upvote an answer from Piotr :) He solved the problem before I even came across the question. – Praetorian Nov 05 '14 at 19:19
  • Why not `std::vector`? – milleniumbug Nov 05 '14 at 19:20
  • @Praetorian I'm not writing the answer, and I really like the `make_unique(1024 * 32);` syntax I didnt know about, so go on – Piotr Skotnicki Nov 05 '14 at 19:21
  • @milleniumbug: Do you know a way I can have a vector be 1024*32 length without filling it with 0s? –  Nov 05 '14 at 19:25
  • Wait, does `make_unique` take a size or the actual elements? [cppref](http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) says the size, but Lavavej's code [here](http://stackoverflow.com/questions/7038357/make-unique-and-perfect-forwarding) is the elements. – Barry Nov 05 '14 at 19:35
  • the standardized *array version* of `make_unique` is `return unique_ptr(new typename remove_extent::type[n]());` with `n` as the only argument of type `size_t`, so it is size, not elements – Piotr Skotnicki Nov 05 '14 at 19:47
  • So many comments, so little question/answer upvotes. Not that anyone will see this comment –  Nov 06 '14 at 02:37

1 Answers1

7
auto buf2 = make_unique<char>(1024 * 32);

allocates a single char and initializes it to (1024 * 32) mod 256 (assuming 8 bit char). To allocate an array of chars containing those many elements, use

auto buf2 = unique_ptr<char[]>(new char[1024 * 32]);
//or
auto buf2 = make_unique<char[]>(1024 * 32);

After making that change your program should behave as expected.

Live demo


And you might as well use unique_ptr to manage the FILE as well.

Define a deleter and an alias

auto fcloser = [](FILE *f) { ::fclose(f); };
using unique_file = std::unique_ptr<FILE, decltype(fcloser)>;

And then use it as

unique_file f(fopen("tmpfile", "wb"), fcloser); // use f.get() to access FILE*

You can even define a factory function to cut down on the verbosity some more.

Praetorian
  • 106,671
  • 19
  • 240
  • 328