returning a const char* from a function - c++

I have to replace some char array code. So say I have a class that has an std::string member variable.
class foo
{
private:
std::string _sBar;
public:
const char* getBar() const { return _sBar.c_str(); }
};
existing code expects that const char*'s are returned in the string accessor functions, so I can't return a const std::string reference.
But isn't there some rule that when the stack unwinds that you can no longer trust the return value from the _sBar.c_str() ?

Yes, that's correct. Better if you ask the caller to supply a buffer with a fixed size say, the caller allocates as:
const int MAX = 1000; // choose some suitable value
char buff[MAX];
And the caller has a foo object,
foo a;
...
a.getBar(buff, MAX);
...
And you define getBar as:
void getBar(char *buffer, int size) const {
strncpy(buffer, _sBar.c_str(), size -1);
buffer[size -1] = 0;
}

you can make a copy of that string with new [ ] operator inside your member function, and it will be stored independently from the class object. In the class:
plublic:
const char* getBar() const {
char * str = new char[_sBar.length()+1];
strcpy(str, _sBar.c_str());
return str;}
In main:
foo object;
///some code
const char* bar = object.getBar();
///some code
delete [] bar;
Note it's good style to free the memory using delete [ ].

Related

How to return/copy values of an unique_ptr<unsigned char[]>?

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;
}
std::unique_ptr is a non-copyable object. If you need a read-only access to it, you have two (main) options:
Return a reference to unique_ptr itself:
const std::unique_ptr<unsigned char[]>& getBuffValue() const
{
return _buff;
}
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.
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.
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.

C++ pass const char* pointer array to object

Dear StackOverFlowers,
I'm having trouble passing a const char* [] to an object. The scenario is as follows.
I have a class UlamScreen which contains a const char* [] with several strings. UlamScreen also contains an object homeScreenMenu.
class UlamScreen {
const char* homeScreenText[5] = {"EVA dun", "Sabine", "TPU dun", "test Wout",
UlamScreenMenu homeScreenMenu;
};
class UlamScreenMenu {
private:
const char* _menuText[];
public:
UlamScreenMenu(const char*[]);
void drawMenu();
};
I want to pass the const char* [] to UlamScreenMenu so I can use it in a member function called void drawMenu, like this:
void UlamScreenMenu::drawMenu() {
for (int i = 0; i < menuItems; i++) {
tft.println(_menuText[i]);
}
}
I passed it to UlamScreenMenu's constructor like this:
UlamScreen::UlamScreen() : homeScreenMenu(homeScreenText) {
}
UlamScreenMenu::UlamScreenMenu(const char* menuText[], int length) {
for(int i = 0; i < length; i++) {
_menuText[i] = menuText[i];
}
}
I thought this would work, but for some reason, it does not. tft.println(_menuText[i]); used with void drawMenu does not send anything to my tft screen. When I use tft.println(_menuText[i]); from within the UlamScreen class it works perfectly.
Just to be clear, I can use the tft object within the UlamScreenMenu class because other functions like tft.drawRect() are working correctly.
What is wrong with this way of passing the const char* []? Thanks in advance.
In C++, you can't declare a member variable of type const char* x[], since this would denote a flexible array member. Flexible array members are a C-feature allowing the last member of a struct to be an array of varying size (cf., for example, Arrays of unknown size / flexible array members). Having parameters of type const char* x[] in functions, however, is supported and has basically the same meaning as const char** x.
If you stick to a member of type const char**, then you'll have to handle memory management in that class. This means: take care of allocating, deallocating, copying, moving, copy-assigning, and move-assigning objets of that class (cf, for example, the rule of 0/3/5).
If - as suggested in the comments - you use standard library collections, e.g. std::vector, these classes will do all this stuff in a reliable manner for you. See the following example illustrating the difference between both:
Note that the C++-version probably would not even take a const char*[]-parameter but directly a const std::vector<const char*> &x-parameter. But I kept the const char*[]-parameter in the constructor to provide the same interface in both variants:
// Variant 1: "old" C-style:
class Menu {
public:
Menu(const char* x[], int length) {
m_x = new const char*[length];
m_length = length;
for (int i=0; i<length; i++) {
m_x[i] = x[i];
}
}
~Menu() {
delete[] m_x;
}
// TODO: implement copy- and move constructors + copy- and move assignments
// ...
void print() {
for (int i=0; i<m_length; i++) {
std::cout << m_x[i] << std::endl;
}
}
private:
const char** m_x = nullptr;
int m_length;
};
#include <vector>
// Variant 2: a C++- way:
class Menu2 {
public:
Menu2(const char* x[], int length) {
m_x.assign(x, x+length);
}
void print() {
for (auto s : m_x) {
std::cout << s << std::endl;
}
}
// Menu2 does not manage memory on its own, hence:
// No special copy/move - constructors/assignments to be implemented.
// No special destructor necessary
private:
std::vector<const char*> m_x;
};
int main() {
const char* x1[3] = {"one","two","three" };
const char* x2[2] = {"eins","zwei" };
// Variant 1
Menu m1(x1, 3);
m1.print();
// Variant 2
Menu2 m2(x2, 2);
m2.print();
}

Storing a string as char[] with placement new and get it back

I want to write a Class which holds information about a string in Memory and which can give it back to me. So i started with a Union which holds the size of a string. (why union doesn't matter here but it need to be union for other types lateron) The constructor get a string passed and should put the string as c_str at the end of the Objekt which i place with placement new.
The class looks like this:
class PrimitivTyp
{
public:
explicit PrimitivTyp(const std::string &s);
std::shared_ptr<std::string> getString() const;
private:
union
{
long long m_long; //use long long for string size
double m_double;
} m_data;
ptrdiff_t m_next;
};
And the impl of the Ctor and the get function looks like this which doesnt work properly i guess.
PrimitivTyp::PrimitivTyp(const std::string& s)
{
m_data.m_long = s.size();
m_next = reinterpret_cast<ptrdiff_t>(nullptr);
//calc the start ptr
auto start = reinterpret_cast<ptrdiff_t*>(this + sizeof(PrimitivTyp));
memcpy(start, s.c_str(), s.size()); //cpy the string
}
std::shared_ptr<std::string> PrimitivTyp::getString() const
{
auto string = std::make_shared<std::string>();
//get the char array
auto start = reinterpret_cast<ptrdiff_t>(this + sizeof(PrimitivTyp)); //get the start point
auto size = m_data.m_long; //get the size
string->append(start, size);//appand it
return string;//return the shared_ptr as copy
}
The Usage should be something like this:
int main(int argc, char* argv[])
{
//checking type
char buffer[100];
PrimitivTyp* typ = new(&buffer[0]) PrimitivTyp("Testing a Type");
LOG_INFO << *typ->getString();
}
This crashes and i don't find the misstake with the Debugger. I think it is something with the position calculation of this.
this + sizeof(PrimitivTyp) is not what you think, you want this + 1 or reinterpret_cast<uint8_t*>(this) + sizeof(PrimitivTyp).
Pointer arithmetic in C and C++ takes into account the type of the pointer.
so with T* t;, (t + 1) is &t[1] (assuming non overload of operator &) or reinterpret_cast<T*>(reinterpret_cast<uint8_t>(t) + sizeof(T)).

How do I capture a smart pointer in a lambda?

What is best way to capture a smart pointer in a lambda? One attempt of mine lead to a use-after-free bug.
Example code:
#include <cstring>
#include <functional>
#include <memory>
#include <iostream>
std::function<const char *(const char *)> test(const char *input);
int main()
{
std::cout.sync_with_stdio(false);
std::function<const char *(const char *)> a = test("I love you");
const char *c;
while ((c = a(" "))){
std::cout << c << std::endl;
}
return 0;
}
std::function<const char *(const char *)> test(const char *input)
{
char* stored = strdup(input);
char *tmpstorage = nullptr;
std::shared_ptr<char> pointer = std::shared_ptr<char>(stored, free);
return [=](const char * delim) mutable -> const char *
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
}
fails, as shown by AddressSanitizer.
A lambda (even one with a universal capture like [=]) only actually captures variables used within its definition. Since in your example, pointer is never used inside the lambda, it's not captured and thus when it goes out of scope, it's the last shared pointer referring to stored and free() is called.
If you want to capture pointer, you could force its use:
return [=](const char * delim) mutable -> const char *
{
pointer;
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
However, this is rather hackish. You want your functor stateful and with nontrivial state management. To me, this is a strong indicator an actual named class (instead of a lambda) would be in order. So I would change it like this:
std::function<const char *(const char *)> test(const char *input)
{
struct Tokenizer
{
std::shared_ptr<char> pointer;
char* stored;
char* tmpstorage;
explicit Tokenizer(char* stored) : pointer(stored, free), stored(stored), tmpstorage(nullptr) {}
const char* operator() (const char * delim)
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
}
};
return Tokenizer(strdup(input));
}
Just capture the variable by value and let the copy constructor and destructor worry about ownership semantics- that's what smart pointers are for.

c++ pass char array to function and change it

I try to make a function that can change the content of a specified char array
void change_array(char *target)
{
target="hi";
}
int main()
{
char *a[2];
change_array(a[1]);
cout<<*(a[1]);
}
But then the content of a[1] stays at 0x0(void)
First, your function has a copy of the pointer passed to it, so there is no effect seen on the caller side. If you want to modify the function argument, pass a reference:
void change_array(char*& target) { ... }
// ^
Second, you cannot/should not bind a non-const pointer to a string literal. Use const char* instead.
void change_array(const char*& target) { ... }
// ^^^^^ ^
int main()
{
const char* a[2];
change_array(a[1]);
cout<<*(a[1]);
}
When you pass an argument to a function, it's normally passed by value, meaning its value is copied. If you want to change it you have to pass it by reference. The same goes for pointers, if you want to change a pointer then you need to pass it by reference as well:
void change_array(const char*& target) { ... }
You need to pass it as a reference:
void change_array(char*&target)
{
target="hi";
}
Otherwise, you will just change the local copy of target, which won't make any difference to the value outside of the function.
Try this design instead:
std::string get_string()
{
return "hi";
}
int main()
{
std::string a[2];
a[1] = get_string();
std::cout<< a[1];
}
Salient points:
return by value
use std::string