avoiding unnecessary allocations for temporaries, r-value destructor - c++

I have a many, MANY strings that are almost never modified after creation and access times to them is not really a concern. I have to minimize the memory usage so I opted to writing a class instead of using std::string which has to hold extra data such as capacity and length to conform with the standard. This change resulted in reduction of ~%30 memory usage.
To achieve this, I have written a class just wraps C-style null-terminated strings internally and manages the buffer so the class just consists of a pointer data member and it provides enough interface to rarely access and work with it like std::string.
I would like to avoid boilerplate code and allow transparent conversions from std::string and to std::string. So can I avoid allocating/copying the data from std::string on edge cases such as when temporary is needed? Consider this:
class A {
public:
A(const char* p) : p_{std::strdup(p)} { }
~A() { free(p_); }
A& append(const A&);
private:
char* p_;
};
Now in the following code:
A a;
a.append("test");
A temporary object will be created, allocating and copying the data. Then it will be immediately destroyed. The question is, is there a way to avoid this without creating a version of every function such as A& append(const char*). I would also like to support the transparent conversions for std::string so it will automatically become 3 versions of each function.
What effects will the following approach have:
class A {
public:
A(const char* p) : p_{std::strdup(p)} { }
A(const char* p) &&
: p_{p} {
}
~A() { free(p_); }
~A() && { /* nothing */ }
A& append(const A&);
private:
char* p_;
};
If this does not work, what strategy can I apply to solve this problem?

What effects will the following approach have:
A(const char* p) &&
~A() &&
The most likely effect is compilation error, since standard doesn't allow ref-qualifiers on c/d-tor.
I recommend implementing A::c_str just like strings do, and use the following helper from a template:
template<class Str>
const char* c_str_help(const Str& str) {
return str.c_str();
}
const char* c_str_help(const char* str) {
return str;
}
class A {
// ...
const char* c_str() const { return p_; }
template<class Str>
A& append(const Str& str) {
const char* s = c_str_help(str);
// implement using const char* s
}
};
PS: I recommend using a unique_ptr<char, void(*)(void*)> instead of a bare pointer for much easier implementation.

A bit similar to user2079303's approach, with SFINAE so we don't hinder overload resolution:
namespace detail_A {
char const *getString(std::string const &str) {
return str.c_str();
}
char const *getString(char const *str) {
return str;
}
// More `getString`s as needed...
template <class T>
using enableString = decltype(getString(std::declval<T>()));
}
class A {
// ...
template <class T, class = detail_A::enableString<T>>
A &append(T const &str) {
char const *p = detail_A::getString(str);
std::cout << "Appending \"" << p << "\"\n";
return *this;
}
};
See it live on Coliru

Related

C++ class override for const and non-const reference member

So I'm making a bitmask class that stores a reference to an std::byte as a member and the index of the individual bit to allow accessing the value of that bit and also assigning to that bit. I also want it to be possible for the value of the std::byte passed to optionally be a const, and if it is a const, I want the class itself to be considered a const or at least make sure operations that may change the underlying value of the std::byte (such as assignment) do not work. However I don't see a way to implement it without copypasting code which I consider to be too complicated. Is there an easier way to get around this? This is my current code for the bitmask class:
class bitmask
{
public:
bitmask(std::byte &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
std::byte &_chunk;
std::uint_fast8_t const _index;
};
What I want is to basically make a variant of it where chunk is a const reference and the assignment operator doesn't exist, without copy-pasting existing code to avoid reptition.
PS: I don't mind using any C++ standard, including C++20, as long as it solves the problem elegantly.
One option is to turn bitmask into a template and use SFINAE + type traits to alter the behavior:
// vvv defaults to non-const, change if desired
template<typename Chunk = std::byte>
class bitmask
{
static_assert(std::is_same_v<std::remove_const_t<Chunk>, std::byte>);
public:
bitmask(Chunk &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
template<bool Enable = !std::is_const_v<Chunk>, typename = std::enable_if_t<Enable>>
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
Chunk &_chunk;
std::uint_fast8_t const _index;
};
When using C++17 or newer, template arguments need not be supplied manually as class template argument deduction will infer Chunk based on the argument passed to bitmask's constructor. Earlier versions of C++ can use a make_bitmask factory + type aliases to accomplish similar aesthetics, though unfortunately the const and non-const variants will necessarily have to be spelled out differently.
So, despite there being some really nice answers here, I didn't find any of them particularly elegant, so I decided to delve deeper and solve my own problem. Note that this solution isn't entirely mine, and was originally inspired by #ildjarn 's answer, so props to them as well.
This is how I ended up solving my problem
// Class to mask reference to individual bit
template <bool is_const = false>
class bitmask
{
public:
using ChunkType = std::conditional_t<is_const, std::byte const, std::byte>;
bitmask(ChunkType &chunk, std::uint_fast8_t index) noexcept
: _chunk(chunk), _index(index){};
bitmask(bitmask const &source) = default;
operator bool() const noexcept
{
return static_cast<bool>((_chunk >> (7 - _index)) & std::byte{1});
}
template <typename = std::enable_if_t<!is_const>>
bitmask &operator=(bool val) noexcept
{
_chunk = ((_chunk & ~(std::byte{1} << (7 - _index))) |
(std::byte{val} << (7 - _index)));
return *this;
}
private:
ChunkType &_chunk;
std::uint_fast8_t const _index;
};
bitmask(std::byte &, std::uint_fast8_t)->bitmask<false>;
bitmask(std::byte const &, std::uint_fast8_t)->bitmask<true>;
So basically, the class is a template now which takes a boolean value depending on whether the byte referenced to is a const or not, and I also added template argument deduction hints for the constructor so the constness is automatically deduced. I also made operator= only work if is_const is false.
This is what pointers allow. Either completely constant or completely variable. So, a true-false statement could always be made.A template class that deduces of being constant or not as well.
template<class T>
class overload {
public:
overload(T t): t(t) {
}
~overload() {}
T get() {
if(std::is_const<T>::value)
clog <<"const\t " <<t <<endl;
else if(! std::is_const<T>::value)
clog <<"variable\t " <<t <<endl;
return this->t;
}
T set(T t) {
this->t= t;
}
private:
T t;
};
class test {
public:
test(const int * const _t) : _t(_t) {}
test(int *t) : t(t), _t(NULL) {}
~test() {}
int get() { return *(this->t); }
void set(int *t) { this->t= t; }
const int * const _get() { return (this->_t); }
int __get( ) {
return (_t==NULL)?*t:*_t;
}
//void _set(const int * const _t) { this->_t= _t; }
private:
int *t;
const int *const _t;
};
int main(int argc, char*argv[]) {
int n;
const int m= 99;
n= 100;
overload<int> o(n);
overload<const int> _o(m);
::cout <<o.get() <<endl;
::cout <<_o.get() <<endl;
test t(&n), _t(&m);
::cout <<t.get() <<"\t" <<*_t._get() <<"\t" <<t.__get() <<"\t" <<_t.__get() <<endl;
return 0;
}

How to initialize field from type "const char*" in this case?

given class with field const char* filename; so that the name of the class is for example MyClass.
#include <cstring>
class MyClass{
const char* filename;
public:
MyClass(const char* name);
};
How can I initialize the field filename by name?
NOTE: I must do it with strcpy function.
Is there a way to do this with a initialization list?
Is there a way to do this with a initialization list?
There is, you need to use strdup function:
class MyClass {
const char* filename;
public:
MyClass(const char* name)
: filename(strdup(name))
{
if(!filename)
throw std::bad_alloc(); // strdup failed.
}
~MyClass() {
free(const_cast<char*>(filename));
}
MyClass(MyClass const&) = delete;
MyClass& operator=(MyClass const& b) = delete;
};
MyClass::MyClass(char const* filename)
: filename(strcpy(new char[strlen(filename) + 1], filename))
// ^^^ space for trailing 0!
{ }
As using new, in case of allocation failure a std::bad_alloc will be thrown and strcpy never be called, so we are fine.
Do not forget to delete[] filename; in the destructor (not free, you did not malloc!), otherwise you have a memory leak.
Edit (stealing the ideas from Maxim's comments...):
Using a lambda, you could profit from the more efficient memcpy:
MyClass::MyClass(char const* filename)
: filename([](char const* value)
{
size_t len = strlen(filename) + 1;
return reinterpret_cast<char*>(memcpy(new char[len], value, len));
}())
{ }
You get all this trouble for free, though, if you switch to std::string instead:
MyClass
{
std::string filename;
public:
MyClass(char const* filename) : filename(filename) { }
};
You don't even need an explicit destructor any more (provided there is nothing else to clean up...) – use filename.c_str() in a char const* getter, if needed.
Working with char* is very tricky. I recommend you to use string to store filename. But you still want to use char*. You can try as follows:
MyClass(const char* name)
{
filename = new char[100];
for(int i=0;name[i]!='\0';i++)
{
filename[i]=name[i];
}
}

`noexcept` specifier for getters and setters

Let's say I have the following code:
class A {
public:
void SetInteger(const int val) noexcept { integerMember = val; }
void SetString(const std::string& val) { stringMember = val; }
int GetInteger() const noexcept { return integerMember; }
std::string GetString() const { return stringMember; }
private:
int integerMember;
std::string stringMember;
}
Using noexcept for integral types and pointers seems for me pretty obvious.
But what are recommendations in case of not integral types like classes and structures that do not throw exceptions in constructor/copy-constructor and constructors of their parts explicitly (meaning using throw in constructor body)?
You should avoid noexcept specifiers for functions which may throw (unless you're prepared to have your code call std::terminate()). Explicit throw specifiers are deprecated, so don't rely on them, rather use the noexcept operator. For example
template<typename T>
class Foo
{
T m_datum;
public:
Foo& SetDatum(T const&x) noexcept(noexcept(m_datum=x))
{
m_datum = x;
return *this;
}
};
Outside of special member functions, noexcept is not that useful. But if you want it:
void SetString(const std::string& val)
noexcept(std::is_nothrow_copy_assignable<std::string>::value) {
}
First way for getter:
const std::string& GetString() const noexcept {return stringMember; }
Second way is for setter:
void SetString(std::string&& val) noexcept {
swap(stringMember, val);
}

Issue with returning a char* which is a struct

I am new to C++, and I am trying to return the struct declared within a class via char*.
#include<iostream>
using namespace std;
#include <cstring>
class test
{
public:
struct pair
{
int a,b;
};
test(){
pir=new pair;
pir->a=1;
pir->b=2;
}
void readx(char* str)
{
char* str2=new char[sizeof(pair)+1];
str2=reinterpret_cast<char*>(pir);
strncpy(str,str2,sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr;
t.readx(ptr);
cout<<*((int*)ptr)<<endl;
cout<<*((int*)ptr+4)<<endl;
return 0;
}
I have tried multiple ways but still failed to return a char* that can be reinterpreted into the struct. Actually the returned char* can only hold the first parameter, losing information about the second parameter, despite that I have used strncpy function. The output of this test code is
1
0
How could I return the everything about struct within the class?
cout<<*((int*)ptr+4)<<endl;
This line should be:
cout<<*((int*)ptr+1)<<endl;
Because you have convert ptr to int *, which +1 means move pointer to next 4 bytes (size of int is 4).
You've got serious problems with your code. If it's really working, it's working only by accident.
Whether it's strncpy or memset you use it doesn't matter too much because you are passing unitialized pointer to the functions which writes to it:
char* ptr;
t.readx(ptr);
Where does ptr point to? It may point almost anywhere and using it as memcpy target is unpredictable. If you are not very unlucky, you will get a segfault/access violation.
Your readx method does some crazy thing:
char* str2 = new char[sizeof(pair)+1];
str2 = reinterpret_cast<char*>(pir);
Here you first alocate some storage and assign its address to str2 then you re-assign it to address of pir. You can never delete[] memory allocated by new[] so you introduce a memory leak.
Constructor of class test allocates memory using new but you don't have corresponding destructor calling delete -> memory leak.
Then there is your ptr+4 problem which was already pointed by the others. Here you can find the code corrected to the point where you can expect it to do what you want.
#include <iostream>
#include <cstring>
using namespace std;
class test
{
public:
struct pair
{
int a, b;
};
test() : pir{ new pair() }
{
pir->a = 1;
pir->b = 2;
}
~test() { delete pir; }
void readx(char* str)
{
memcpy(str, reinterpret_cast<char*>(pir), sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr = new char[sizeof(test::pair)];
t.readx(ptr);
cout << *((int*)ptr) << endl;
cout << *((int*)ptr + 1) << endl;
delete[] ptr;
return 0;
}
When you understand the basic issues your code have read about the rule of five. For the test class you would add something like this:
#include <algorithm>
class test
{
//...
test(test const& other) : pir{ new pair() }
{
pir->a = other.pir->a;
pir->b = other.pir->b;
}
test& operator=(test const& other)
{
test copy(other);
swap(*this, copy);
return *this;
}
test(test&& other) noexcept : pir{ nullptr }
{
swap(*this, other);
}
test& operator=(test&& other) noexcept
{
swap(*this, other);
return *this;
}
friend void swap(test& lhs, test& rhs)
{
std::swap(lhs.pir, rhs.pir);
}
};
You are incrementing the int pointer by 4. This points 4 integers ahead. That's not what you want.
cout<<*((int*)ptr+1)<<endl;
That should get you b.

What are good ways to avoid copying if method's caller doesn't need ownership of the data?

Here is the problem I was thinking about lately. Let's say our interface is a member function that returns object which is expensive to copy and cheap to move (std::string, std::vector, et cetera). Some implementations may compute the result and return a temporary object while others may simply return a member object.
Sample code to illustrate:
// assume the interface is: Vec foo() const
// Vec is cheap to move but expensive to copy
struct RetMember {
Vec foo() const { return m_data; }
Vec m_data;
// some other code
}
struct RetLocal {
Vec foo() const {
Vec local = /*some computation*/;
return local;
}
};
There are also various "clients". Some only read the data, some require an ownership.
void only_reads(const Vec&) { /* some code */ }
void requires_ownership(Vec) { /* some code */ }
Code above composes well, but is not as efficient as it could be. Here are all combinations:
RetMember retmem;
RetLocal retloc;
only_reads(retmem.foo()); // unnecessary copy, bad
only_reads(retloc.foo()); // no copy, good
requires_ownership(retmem.foo()); // copy, good
requires_ownership(retloc.foo()); // no copy, good
What is a good way to fix this situation?
I came up with two ways, but I'm sure there is a better solution.
In my first attempt I wrote a DelayedCopy wrapper that holds either a value of T or a pointer to const T. It is very ugly, requires extra effort, introduces redundant moves, gets in the way of copy elision and probably has many other problems.
My second thought was a continuation-passing style, which works quite well but turns member functions into member function templates. I know, there is std::function, but it has its overhead so performance-wise it may be unacceptable.
Sample code:
#include <boost/variant/variant.hpp>
#include <cstdio>
#include <iostream>
#include <type_traits>
struct Noisy {
Noisy() = default;
Noisy(const Noisy &) { std::puts("Noisy: copy ctor"); }
Noisy(Noisy &&) { std::puts("Noisy: move ctor"); }
Noisy &operator=(const Noisy &) {
std::puts("Noisy: copy assign");
return *this;
}
Noisy &operator=(Noisy &&) {
std::puts("Noisy: move assign");
return *this;
}
};
template <typename T> struct Borrowed {
explicit Borrowed(const T *ptr) : data_(ptr) {}
const T *get() const { return data_; }
private:
const T *data_;
};
template <typename T> struct DelayedCopy {
private:
using Ptr = Borrowed<T>;
boost::variant<Ptr, T> data_;
static_assert(std::is_move_constructible<T>::value, "");
static_assert(std::is_copy_constructible<T>::value, "");
public:
DelayedCopy() = delete;
DelayedCopy(const DelayedCopy &) = delete;
DelayedCopy &operator=(const DelayedCopy &) = delete;
DelayedCopy(DelayedCopy &&) = default;
DelayedCopy &operator=(DelayedCopy &&) = default;
DelayedCopy(T &&value) : data_(std::move(value)) {}
DelayedCopy(const T &cref) : data_(Borrowed<T>(&cref)) {}
const T &ref() const { return boost::apply_visitor(RefVisitor(), data_); }
friend T take_ownership(DelayedCopy &&cow) {
return boost::apply_visitor(TakeOwnershipVisitor(), cow.data_);
}
private:
struct RefVisitor : public boost::static_visitor<const T &> {
const T &operator()(Borrowed<T> ptr) const { return *ptr.get(); }
const T &operator()(const T &ref) const { return ref; }
};
struct TakeOwnershipVisitor : public boost::static_visitor<T> {
T operator()(Borrowed<T> ptr) const { return T(*ptr.get()); }
T operator()(T &ref) const { return T(std::move(ref)); }
};
};
struct Bar {
Noisy data_;
auto fl() -> DelayedCopy<Noisy> { return Noisy(); }
auto fm() -> DelayedCopy<Noisy> { return data_; }
template <typename Fn> void cpsl(Fn fn) { fn(Noisy()); }
template <typename Fn> void cpsm(Fn fn) { fn(data_); }
};
static void client_observes(const Noisy &) { std::puts(__func__); }
static void client_requires_ownership(Noisy) { std::puts(__func__); }
int main() {
Bar a;
std::puts("DelayedCopy:");
auto afl = a.fl();
auto afm = a.fm();
client_observes(afl.ref());
client_observes(afm.ref());
client_requires_ownership(take_ownership(a.fl()));
client_requires_ownership(take_ownership(a.fm()));
std::puts("\nCPS:");
a.cpsl(client_observes);
a.cpsm(client_observes);
a.cpsl(client_requires_ownership);
a.cpsm(client_requires_ownership);
}
Output:
DelayedCopy:
Noisy: move ctor
client_observes
client_observes
Noisy: move ctor
Noisy: move ctor
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
CPS:
client_observes
client_observes
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
Are there better techniques to pass values that avoid extra copies yet are still general (allow returning both temporaries and data members)?
On a side note: the code was compiled with g++ 5.2 and clang 3.7 in C++11. In C++14 and C++1z DelayedCopy doesn't compile and I'm not sure whether it's my fault or not.
There are probably thousands of 'correct' ways. I would favour one in which:
the the method that delivers the reference or moved object is explicitly stated so no-one is in any doubt.
as little code to maintain as possible.
all code combination compile and do sensible things.
something like this (contrived) example:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
// an object that produces (for example) strings
struct universal_producer
{
void produce(std::string s)
{
_current = std::move(s);
// perhaps signal clients that there is something to take here?
}
// allows a consumer to see the string but does not relinquish ownership
const std::string& peek() const {
// will throw an exception if there is nothing to take
return _current.value();
}
// removes the string from the producer and hands it to the consumer
std::string take() // not const
{
std::string result = std::move(_current.value());
_current = boost::none;
return result;
}
boost::optional<std::string> _current;
};
using namespace std;
// prints a string by reference
void say_reference(const std::string& s)
{
cout << s << endl;
}
// prints a string after taking ownership or a copy depending on the call context
void say_copy(std::string s)
{
cout << s << endl;
}
auto main() -> int
{
universal_producer producer;
producer.produce("Hello, World!");
// print by reference
say_reference(producer.peek());
// print a copy but don't take ownership
say_copy(producer.peek());
// take ownership and print
say_copy(producer.take());
// producer now has no string. next peek or take will cause an exception
try {
say_reference(producer.peek());
}
catch(const std::exception& e)
{
cout << "exception: " << e.what() << endl;
}
return 0;
}
expected output:
Hello, World!
Hello, World!
Hello, World!
exception: Attempted to access the value of an uninitialized optional object.