0

I have a simple class with one attribute std::unique_ptr<unsigned char[]> in C++. I want to have a function that converts string to std::unique_ptr<unsigned char[]>, other to convert float to std::unique_ptr<unsigned char[]>, and a third to return the attribute std::unique_ptr<unsigned char[]>. My header is compiling but the source CPP is not. Even the return attribute is not compiling.

#include <memory>
class SkinnyBuffer {
private:
    std::unique_ptr<unsigned char[]> _buff;
public:
    ~SkinnyBuffer();
    SkinnyBuffer();
    void setBuffValue(float f);
    void setBuffValue(std::string str);
    std::unique_ptr<unsigned char[]>* getBuffValue();
};

#include "utils/SkinnyBuffer.h"
SkinnyBuffer::~SkinnyBuffer() { }
SkinnyBuffer::SkinnyBuffer() { }
void SkinnyBuffer::setBuffValue(float f) {
    // How to implement it
    _buff = f;
}
void SkinnyBuffer::setBuffValue(std::string str) {
    _buff = std::unique_ptr<unsigned char[]>(str.data(), str.data() + str.length());
}
std::unique_ptr<unsigned char[]>* SkinnyBuffer::getBuffValue() {
    return &_buff;
}
Felipe
  • 3,986
  • 5
  • 29
  • 62
  • 1
    You can't return `std::unique_ptr` by value, because it is unique and your `getBuffValue` returns its copy. Return either a reference to it, or a reference to the managed object, `*_buff`. – Evg Oct 10 '18 at 11:47
  • 3
    " // How to implement it" this isnt your first question on how to "convert" a float to a char array and you are quite persistent in assuming that there is some obvious unique way to do that. There is not, you need to say what that conversion should be – 463035818_is_not_a_number Oct 10 '18 at 11:48
  • @Evg - no. This also does not compile – Felipe Oct 10 '18 at 11:52
  • 2
    `std::unique_ptr`, as the name suggest, can have only one owner at any given time. If you want to pass the ownership to someone else, you need to give up your ownership (you cannot keep that pointer in `SkinnyBuffer` then). – Yksisarvinen Oct 10 '18 at 11:53
  • I have an implementation which uses `std::vector ` and other which uses `unsigned char*`. THe vector impl is 10 times slower than the plain char array. So I was going with the plain char array. However, when I use a methods to return the char array `unsigned char * readRequest()` in a child class I get UB (only the method that converts float to char array). so one advised me to use unique_ptr https://stackoverflow.com/questions/52723208/how-to-return-the-real-value-unsigned-char-array-in-my-case-and-not-a-pointer – Felipe Oct 10 '18 at 12:34
  • What did you do to make a vector so much slower than a C array? You can instantiate a vector, with it's proper contents, in one go. – Caleth Oct 10 '18 at 12:50
  • Probably, you make a lot of unnecessary copies of it. It can't be that slow. – Evg Oct 10 '18 at 13:15

3 Answers3

3

std::unique_ptr is a non-copyable object. If you need a read-only access to it, you have two (main) options:

  1. Return a reference to unique_ptr itself:

    const std::unique_ptr<unsigned char[]>& getBuffValue() const
    {
        return _buff;
    }
    
  2. Return a const pointer to the managed array:

    const unsigned char* getBuffValue() const
    {
        return _buff.get();
    }
    

To assign a string to the buffer, you can do:

void setBuffValue(const std::string& str)
{
    _buff = std::make_unique<unsigned char []>(str.length() + 1);
    std::copy_n(str.c_str(), str.length() + 1, _buff.get());
}

Note that you have to copy the terminating null character to your buffer. Otherwise it will be almost useless for the outside world because its length will not be known to the user.

But do you really need std::unique_ptr<unsigned char[]>? std::vector seems to be more appropriate here.

Evg
  • 20,870
  • 4
  • 34
  • 69
  • I am trying to use vector and see if I get any UB on the child classes or when I read the value in other classes. – Felipe Oct 10 '18 at 12:44
  • 1
    @FelipeOliveiraGutierrez, if you get any UB and seg. fault, it is not because of `std::vector` itself. Make sure you don't access memory that has been freed. – Evg Oct 10 '18 at 12:46
0

You cannot do it this way. You have to copy the content of the string in a new array that is pointed by the unique pointer and then return the unique pointer.

The other option is to return a string in your two inherited classes.

Matthieu Brucher
  • 19,950
  • 6
  • 30
  • 49
0

Return a view of the data in buff_, don't try to copy it.

const unsigned char * SkinnyBuffer::getBuffValue() const {
    return _buff.get();
}

You can use that value until the SkinnyBuffer is destroyed or modified.

Caleth
  • 35,377
  • 2
  • 31
  • 53