I have a C datastructure representing a vector of boolean values; for reasons outside of my control the bools' are stored internally as integers with two magical values (not 0 and 1 ...) representing true and false. I have created a C++ class wrapping this C structure, and it works nicely. I have implemented the set()and get()methods as:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
This works ok; but ideally I would like to overload operator[], however it is not clear to me how/if I can do that - due to special transformation between bool and the integer values?
struct pseudo_reference {
operator bool()const&&{
return c->get(index);
}
pseudo_reference operator=(bool b)&&{
c->set(index, b);
return {c,index};
}
// sometimes having named functions is useful:
bool get() const&& {
return std::move(*this);
}
void set(bool b)&& {
std::move(*this) = b;
}
pseudo_reference()=delete;
private:
Class* c;
size_t index;
pseudo_reference(pseudo_reference&&o)=default; // not exposed
pseudo_reference(Class* pc, size_t i):c(pc),index(i){}
friend class Class;
};
In Class:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
I stored both a pointer and an index, so I avoid reimplementing the logic of get/set in my pseudo_reference. Such pseudo_references are likely to be short-lived, so size optimization probably isn't important.
I blocked all non-rvalue operations to discourage storing a pseudo_reference. You can make said operations non-rvalue restricted relatively harmlessly, but in my experience pseudo_references are values that behave like references, so it is better if they don't persist.
Someone can still store a pseudo_reference via auto&& x = c[33];, but using it without moveing it won't be possible. Hopefully that catches most error-prone uses of it. auto x = c[33]; won't work.
To implement operator[](), you need to return a proxy object that does the actual assignment when it appears on the left-hand-side of =:
struct proxy {
proxy& operator=( bool value ) {
c_.c_ptr[ index_ ] = value ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
operator bool() const { // for when it's just used normally, not =
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
private:
Class &c_;
size_t const index_;
proxy( Class &c, size_t index ) : c_( c ), index_( index ) { }
friend class Class;
}
class Class {
public:
proxy operator[]( size_t index ) {
return proxy( *this, index );
}
bool operator[]( size_t index ) const { // read-only access is easy
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
// ...
};
Or something like that.
You can return a wrapper helper class which handles assignment for you.
struct WrapMe {
c_ptr_T &value;
WrapMe(c_ptr_T &_value) : value(_value) {}
// handles assignment of bool values
WrapMe & operator=(const bool b) {
value = (b) ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
// handles cast to bool
operator bool() const { return value == SPECIAL_TRUE_VALUE; }
};
class Class {
WrapMe operator[](const int idx) { return WrapMe(c_ptr[idx]); }
// ...
};
Related
I am trying to overload the == operator for a class Structure, which is a multi-type container. My approach for other operations has been to have an empty virtual function in the Structure class and override it in the derived Element template class.
This is because, when adding the elements to the vector, I am wrapping them into Element and storing them in the vector as StructPtrs. In order to know the type of each StructPtr, I must do the above (I cannot use dynamic_cast) because it will only know its type when it calls on the overridden function in the Element class.
class Structure;
using StructPtr = std::shared_ptr<Structure>;
template<class T>
class Element;
// Make sure to define your printElement function, too.
void printElement(std::ostream& out, const Structure& s);
// Define your `Structure` class here
class Structure{
public:
Structure() = default;
virtual ~Structure() = default;
Structure(const Structure& oldStruct){
for(auto element : oldStruct.elements)
elements.emplace_back(element->getCopy());
}
Structure operator = (const Structure& otherStruct){
if(this == &otherStruct)
return *this;
if(elements.size() != otherStruct.elements.size()){
elements.clear();
}
std::copy(otherStruct.elements.begin(), otherStruct.elements.end(), std::back_inserter(elements));
return *this;
}
bool operator == (const Structure& other) const{
if(elements.empty() && other.elements.empty())
return true;
bool result = false;
for(int i = 0; i < other.elements.size(); i++){
if(elements[i]->equals(*(other.elements[i])))
result = true;
else result = false;
}
return result;
}
virtual bool equals( Structure& otherStruct) const { }
template<class T>
void add(T obj){
elements.emplace_back(std::make_shared<Element<T>>(obj));
}
virtual StructPtr getCopy() const {}
virtual void printDerived(std::ostream& out) const{}
void print(std::ostream& out) const{
for(auto element : elements)
element->printDerived(out);
}
std::vector<StructPtr> elements;
};
template<class T>
class Element : public Structure{
public:
Element() = default;
//Element(int element) : element(element) { }
//Element(Structure element) : element(element) { }
//Element(std::string element) : element(element) { }
Element(T _element) : element(_element) { }
Element( const Element<T>& oldElement){
element = oldElement.element;
}
bool equals ( Structure& otherStruct) const override{
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
auto other = static_cast<Element&>(otherStruct);
return element == other.element;
}
StructPtr getCopy() const override {
StructPtr newStructPtr;
if constexpr (std::is_same_v<T, Structure>){
Structure newStruct(*this);
newStructPtr = std::make_shared<Element<T>>(newStruct);
}
else
newStructPtr = std::make_shared<Element<T>>(*this);
return newStructPtr;
}
void printDerived(std::ostream& out) const override {
printElement(out, element);
}
T element;
};
void printElement(std::ostream& out, const Structure& s){
s.print(out);
}
The problem is, for ==, it has a structure in the function argument. This approach does not work, because when I pass this as an argument down to the Element class, it is still a Structure and not an Element.
Right now, my code works for every test case, except for the case of nested structures. When I try to compare two structures with other structures in them, I get this error:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==26776==ERROR: AddressSanitizer: SEGV on unknown address 0x000104fbffb8 (pc 0x00010423ec88 bp 0x00010423ec64 sp 0x00016bbc79d0 T0)
==26776==The signal is caused by a UNKNOWN memory access.
Why is my code resulting in this error, and how do I fix it?
Your operator== is doing the right thing by using a virtual equals() method, however the rest of it is not implemented correctly. You are treating the result variable the wrong way, and worse the code has undefined behavior if the two vectors have different sizes. Try this instead:
class Structure{
public:
...
bool operator == (const Structure& other) const {
if (elements.size() != other.elements.size())
return false;
for(size_t i = 0; i < other.elements.size(); ++i) {
if (!elements[i]->equals(*(other.elements[i])))
return false;
}
return true;
}
...
};
Now, that being said, you can't make Element::equals() accept an Element when you are calling it polymorphically from Structure, like you are asking for (at least, not without casting).
But, what you can do (and need to do) is make Element::equals() check if the input Structure is actually an Element or not. You have to do that anyway so that you can differentiate between Element<X> and Element<Y> when X and Y are different types. The way you are using static_cast is not doing that validation, so you will have undefined behavior when you cast to the wrong type. And you can't do the check with std::is_same_v (a compile-time check), either. You must use dynamic_cast (a runtime check), eg:
template<class T>
class Element : public Structure{
public:
...
bool equals (const Structure& otherStruct) const override {
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
else {
auto other = dynamic_cast<const Element<T>*>(&otherStruct);
return (other && element == other->element);
}
}
...
};
However, since you say you can't use dynamic_cast (why?), you will just have to tag every Element based on which T it is created with, and then you can compare the tags for equality before casting, eg:
#include <typeinfo>
template<class T>
class Element : public Structure{
public:
...
const std::type_info& getTypeInfo() const {
return typeid(T);
}
bool equals (const Structure& otherStruct) const override {
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
else if (getTypeInfo() == otherStruct.getTypeInfo()) {
return element == static_cast<const Element<T>&>(otherStruct).element;
}
else
return false;
}
...
};
I have a C++ class which simulates an array and for manipulating its members I implemented two functions: set(size_t index, size_t value) and get(size_t index). I would like to overload the [] operator to have the following functionality:
MyCustomArray[index] = value //->set(size_t index, size_t value)
And
value = MyCustomArray[index] //->get(size_t index)
get can be easily implemented with overload, but I don't know how to implement set because I need the parameter value beforehand.
My class is an implementation of a fixed-word array (elements in the array have at most P bits, where P is a parameter and it can be less than the regular machine word). To support this functionality, set and get manipulate a range of bits of a value in a regular C/C++ array.
Is it possible to overload in this scenario?
Thanks in advance!
This is just like what std::vector::operator[] is doing - using a proxy object.
class MyCustomArray
{
public:
using value_type = unsigned;
class Proxy
{
public:
friend class MyCustomArray;
operator value_type() const
{
return m_customArray.get(m_index);
}
Proxy & operator=(value_type value)
{
m_customArray.set(m_index, value);
return *this;
}
private:
Proxy(MyCustomArray & customArray, size_t index)
: m_customArray(customArray), m_index(index) {}
MyCustomArray & m_customArray;
size_t m_index;
};
value_type operator[](size_t index) const
{
return get(index);
}
Proxy operator[](size_t index)
{
return Proxy(*this, index);
}
value_type get(size_t index) const;
void set(size_t index, value_type value);
private:
/// The data goes here
};
Then
void work(MyCustomArray & arr)
{
// Return a Proxy object, and call operator= over it.
arr[3] = 5;
// arr_2 is of type MyCustomArray::Proxy
auto arr_2 = arr[2];
arr_2 = 1; // modifies arr[2]
unsigned x = arr_2; // gets 1 from arr[2]
// This works, due to auto conversion to value_type:
std::cout << arr_2 << '\n';
}
As mentioned in the comments, this can be accomplished by having operator[] return a proxy object, which is how std::vector<bool> performs its magic.
In your case, it would look something along these lines:
struct MyCustomArray;
struct ArrayMemberRef {
MyCustomArray* target_;
std::size_t index_;
ArrayMemberRef& operator=(std::size_t value);
operator std::size_t();
};
struct MyCustomArray {
ArrayMemberRef operator[](std::size_t index) {
return ArrayMemberRef{this, index};
}
void set(std::size_t index, std::size_t value);
int get(std::size_t index);
};
ArrayMemberRef& ArrayMemberRef::operator=(std::size_t value) {
target_->set(index_, value);
return *this;
}
ArrayMemberRef::operator std::size_t() {
return target_->get(index_);
}
Recently I tried to implement my own version of a smart pointer. The implementation looks a bit like the following:
class Var {
private:
void* value;
unsigned short* uses;
public:
Var() : value(nullptr), uses(new unsigned short(1)) { }
template<typename K>
Var(K value) : value((void*)new K(value)), uses(new unsigned short(1)) { }
Var(const Var &obj) {
value = obj.value;
(*(uses = obj.uses))++;
}
~Var() {
if (value == nullptr && uses == nullptr) return;
if (((*uses) -= 1) <= 0) {
delete value;
delete uses;
value = uses = nullptr;
}
}
Var& operator=(const Var& obj) {
if (this != &obj) {
this->~Var();
value = obj.value;
(*(uses = obj.uses))++;
}
return *this;
}
};
The implementation should be straight forward, as value holds the pointer and uses counts the references.
Please note the pointer is stored as a void* and the pointer class is not fixed to certain (generic) type.
The Problem
Most of the time the smart pointer does it's job... the exception being the following:
class C {
public:
Var var;
C(Var var) : var(var) {}
};
void test() {
std::string string = std::string("Heyo");
Var var1 = Var(string);
C c = C(var1);
Var var2 = Var(c);
}
void main() {
test();
}
When running that code the very first instance, var1, does not get deleted after test has run.
Yes, using a void* is not exactly the finest of methods. Yet lets not get off topic. The code compiles perfectly fine (if one might question my use of sub-assign operator). And if the error would be in the deletion of a void* the reference counter, uses, would be deleted but it is not.
I have checked with the destructors before and they all get called as they should.
Do also note that the programm runs without errors.
Thank You all in advance,
Sheldon
Three big problems I see with your code are:
you are storing the allocated object pointer as a void*, and then calling delete on it as-is. That will not call the object's destructor. You must type-cast the void* back to the original type before calling delete, but you can't do since you have lost the type info after the Var constructor exits.
you have separated the object pointer and the reference counter from each other. They should be kept together at all times. Best way to do that is to store them in a struct, and then allocate and pass that around as needed.
your operator= is calling this->~Var(), which is completely wrong. Once you do that, the object pointed to by this is no longer valid! You need to keep the instance alive, so simply decrement its current reference counter, freeing its stored object if needed, and then copy the pointers from the source Var and increment that reference counter.
Try this alternate implementation instead (Live Demo):
class Var
{
private:
struct controlBlockBase
{
unsigned short uses;
controlBlockBase() : uses(1) { }
virtual ~controlBlockBase() { }
};
template <class K>
struct controlBlockImpl : controlBlockBase
{
K value;
controlBlockImpl(const K &val) : controlBlockBase(), value(val) {}
};
controlBlockBase *cb;
public:
Var() : cb(nullptr) { }
template<typename K>
Var(const K &value) : cb(new controlBlockImpl<K>(value)) { }
Var(const Var &obj) : cb(obj.cb) {
if (cb) {
++(cb->uses);
}
}
Var(Var &&obj) : cb(nullptr) {
obj.swap(*this);
}
~Var() {
if ((cb) && ((cb->uses -= 1) <= 0)) {
delete cb;
cb = nullptr;
}
}
Var& operator=(const Var& obj) {
if (this != &obj) {
Var(obj).swap(*this);
}
return *this;
}
Var& operator=(Var &&obj) {
obj.swap(*this);
return *this;
}
/* or, the two above operator= codes can be
merged into a single implementation, where
the input parameter is passed by non-const
value and the compiler decides whether to use
copy or move semantics as needed:
Var& operator=(Var obj) {
obj.swap(*this);
return *this;
}
*/
void swap(Var &other)
{
std::swap(cb, other.cb);
}
unsigned short getUses() const {
return (cb) ? cb->uses : 0;
}
template<class K>
K* getAs() {
if (!cb) return nullptr;
return &(dynamic_cast<controlBlockImpl<K>&>(*cb).value);
}
};
void swap(Var &v1, Var v2) {
v1.swap(v2);
}
Update: That being said, what Var is doing is basically the same effect as using a std::any wrapped in a std::shared_ptr, so you may as well just use those instead (std::any is in C++17 and higher only, use boost::any for earlier versions):
class Var
{
private:
std::shared_ptr<std::any> ptr;
public:
template<typename K>
Var(const K &value) : ptr(std::make_shared<std::any>(value)) { }
void swap(Var &other) {
std::swap(ptr, other.ptr);
}
long getUses() const {
return ptr.use_count();
}
template<class K>
K* getAs() {
return any_cast<K>(ptr.get());
}
};
void swap(Var &v1, Var &v2) {
v1.swap(v2);
}
UPDATE: I revised some place, and now the problem has changed in some way.
I'm writing a C++ class. Like:
class qqq{
map<int,int> core;
//......
int& operator[](int n){return core[n];};
};
int main(){
qqq a;
a[3]=7;a[5]=0;//Case a
int b=a[3];//Case b
return 0;
}
Although case A and case B are calling the same function(overloaded operator), but case a is used as an lvalue while case b is used as a rvalue.
For some reason, I want to have the effect that if 0 is passed to a[5], delete the node 5 in core. Like:
int& operator[](int n){
if(CASE A && THE VALUE PASSED TO IT IS 0)
core.erase(core.find(n));
else
return core[n];
}
Maybe my description is not accurate.
Here is an implementation of the proxy pattern mentioned in the comments.
Personally, I don't use this, my maps are wrapped in classes that don't provide operator[] at all, instead there are functions like .get(key, default) .init(key), .setdefault(key, default), etc. depending on the class.
// This code is C++11 but it's not essential to the problem.
// The current code calls copy constructors more than necessary.
#include <map>
#include <cassert>
template<class K, class V>
struct zero_map
{
struct proxy
{
std::map<K, V> *container;
K key;
operator V()
{
auto it = container->find(key);
if (it == container->end())
return V();
return *it;
}
void operator = (V value)
{
if (value == V())
{
container->erase(key);
}
else
{
// probably should use .insert() and conditionally assign
(*container)[key] = value;
}
}
};
std::map<K, V> _inner;
proxy operator[](K k)
{
return proxy{&_inner, k};
}
};
int main()
{
zero_map<int, int> foo;
assert (foo._inner.size() == 0);
foo[1] = 0;
assert (foo._inner.size() == 0);
foo[0] = 1;
assert (foo._inner.size() == 1);
foo[0] = 0;
assert (foo._inner.size() == 0);
}
As a comment said, use a proxy class.
template<typename T, size_t BadIndex>
class Element{ // please use a more meaningful name
public:
Element(const size_t index): index(index){}
operator T& (){return value;}
operator T const&() const{return value;}
T &operator =(const T &rhs){
if(index != BadIndex)
value = rhs;
return value;
}
operator T const&() const{return value;}
operator T&(){return value;}
private:
T value;
const size_t index;
};
class qqq{
public:
std::map<int, Element<int, 5>> core;
Element<int> &operator [](size_t index){
auto itt = core.find(index);
if(itt == core.end()){
core.emplace(index, index);
itt = core.find(index);
}
return (*itt).second;
}
};
That should work, but 5 will always give you a garbage result.
You have to always return a value which can be used as left value in the assignment expression. Therefore, I suggest to use a garbage int variable. I declared the garbage as static because we need just one instance of this variable and we don't care its value.
For example,
class qqq{
static int garbage;
map<int,int> core;
//......
int& operator[](int n){
if(CASE A && THE VALUE PASSED TO IT IS 0)
return garbage;
else
return core[n];
}
};
However, this solution is confusing in my point of view because the behaviour completely changes according to what you specify in the square brackets. If the value passed in input is incorrect, I would probably thrown an exception.
* EDIT *
I think you are over complicating the problem using the [] operator. You can easily solve your problem by using setter and getters. For example :
int set(int index, int value){
if( value == 0)
core.erase(core.find(index));
else
return core[index];
}
int get(int index) {
return core[index];
}
The [] allows only for returning a reference, you don't know what is the value used in the assignment.
You question is now clear, unfortunately you will have no way to do that is C++. operator[] is not a getter and a setter : it can only return a reference, and that reference is than used for a mere assignement. At the moment the operator returns its reference, you cannot know what value will be used for a assignement, and you can hardly know how the ref will be used.
IMHO what you need is more :
int getCore(int i) {
return core[i];
}
void setCore(int i, int newval) {
if (newval == 0) {
core.erase(core.find(i));
}
else {
core[i] == newval;
}
I have written a templates class for storing multiple bools in an integer.
Right now, setting and getting each bool is done with explicit functions
bool isBitSet(int index)
{
return static_cast<bool>((block_ >> index) % 2)
}
void setBitOn(int index)
{
block_ |= 1 << index;
}
I believe that the following would work for getting a value, but how would setting work since we can't directly return a reference for a bit?
const bool operator [] (int index) const
{
return static_cast<bool>((block_ >> index) % 2);
}
The same is done in std::vector<bool> and in std::bitset in the standard library. As stated in the reference, std::vector<bool> it returns a proxy class that has its operators overloaded to act as an element of the vector.
You could to that as well.
For a user-friendly example see again the reference for a public interface, it is something like this:
template <class Allocator>
class vector<bool, Allocator> {
// ...
public:
class reference {
friend class vector;
reference();
public:
~reference();
operator bool() const;
reference& operator=(bool x);
reference& operator=(const reference&);
void flip();
};
// ...
};
To implement this class you should store a member pointer to your actual data block and a mask to operate with.
For a real example, in the g++ headers look for member class of std::vector<bool> called std::vector<bool>::_Bit_reference in the file bits/stl_bvector.h.
To clarify the OP with an example:
Let's say you have a class containing 320 bools. You could write it as:
class boolcontainer {
uint32_t data[10];
public:
//default ctor. to initialize the elements with zeros
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
}
You want to add an operator[]. To add a const one is easy:
class boolcontainer {
uint32_t data[10];
public:
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
}
to have a non-const one you need much more. First you need to create a class that represents a reference to your value. You must have some kind of pointer to where the value is stored and (in this case) you need a bitmask to specify one concrete bit. To be able to handle this as a bool& you need to add some operators, namely conversion to bool and operator=:
class reference {
uint32_t *dataptr;
uint32_t mask;
public:
//constructor just initializing members
reference(uint32_t *dataptr_, uint32_t mask_) : dataptr(dataptr_), mask(mask_) {}
//conversion to bool
operator bool() const {
//just like in the getter, but the bitmask is stored now locally
return *dataptr & mask;
}
//sets one single bit represented by mask to b
reference& operator=(bool b) {
if (b) {
*dataptr |= mask;
} else {
*dataptr &= ~mask;
}
return *this;
}
//TODO copy ctor., operator==, operator<
};
Note that the above struct will behave as a bool& -- reading from it reads the value from the data point represented by the pointer and the mask, and similarly, writing to it overwrites the bit at the represented location. I also wrote a constructor that initializes the members.
Now all you need is that your boolcontainer's operator[] should return an object of the above class:
class boolcontainer {
uint32_t data[10];
public:
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
class reference {
... //see above
}
//keep the const version for efficiency
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
//non-const version returns our reference object.
reference operator[](int i) { return reference(&data[i/32], 1 << (i%32)); }
};
And now some code to test it (prints only the first 40 values):
#include <iostream>
#include "boolcontainer.h"
void printboolcontainer(const boolcontainer &bc)
{
//note that this is the constant version
for (int i = 0; i < 40; ++i) {
std::cout << bc[i];
}
std::cout << std::endl;
}
int main()
{
boolcontainer bc;
printboolcontainer(bc);
bc[0] = true;
bc[3] = true;
bc[39] = true;
printboolcontainer(bc);
}