Consider the following class that implements (very basically for the sake of MCVE) small string optimization (assuming little endian, 64 bit pointers, etc.):
class String {
char* data_;
bool sso() const { return reinterpret_cast<uintptr_t>(data_) & 1; }
public:
String(const char * arg = "") {
auto len = strlen(arg);
if (len > 6) {
data_ = new char[len + 1];
memcpy(data_, arg, len + 1);
}
else {
data_ = reinterpret_cast<char*>((uintptr_t)1);
memcpy(reinterpret_cast<char*>(&data_) + 1, arg, len + 1);
}
}
~String() { if (sso() == false) delete data_; }
// ~String() { if (reinterpret_cast<uintptr_t>(data_) & 1 == 0) delete data_; }
};
Note that there are 2 versions of the destructor. When I measured the difference between these 2 versions with Quick C++ Benchmark:
static void CreateShort(benchmark::State& state) {
for (auto _ : state) {
String s("hello");
benchmark::DoNotOptimize(s);
}
}
I got 5.7 times faster running time in the second case with GCC. I don't understand why the compiler cannot generate the same optimized assembly here. What hinders compiler optimizations in case the result of bitwise AND operation is additionally converted into bool? (Though I am not an assembler expert, I can see some differences in the assembly outputs for both variants, but cannot figure out why there are there.)
Benchmark link: http://quick-bench.com/wZhYuffRc1LMwFJ4rx4Xxy330Sw
Godbolt link: https://godbolt.org/z/dAUI_u
With Clang, there is no difference and both variants are fast.
The problem is with conversion to bool, not with inlining. The destructor of the following form causes the same problem:
~String() { if ((bool)(reinterpret_cast<uintptr_t>(data_) & 1) == false) delete data_; }
For this code:
if (reinterpret_cast<uintptr_t>(data_) & 1 == 0) delete data_;
it can be optimized out entirely: 1 == 0 is always 0, and x & 0 is always false for all x. The first case is slower because it is actually doing something.
I suppose you meant:
if ( (reinterpret_cast<uintptr_t>(data_) & 1) == 0) delete data_;
A mnemonic I use for precedence of & | is to recall that in precursors of C, there were not separate operators & and &&; the & operator fulfilled both roles (and you manually convert to boolean range if you wanted a logical comparison). So x == y & z == w was normal code for checking if those two equalities held.
When && was introduced, in order to avoid breaking existing code, && was given lower precedence than &; but & remained unchanged, below ==.
The C++ language did not alter these precedences either, presumably this was purposeful to minimize incompatibilities between the two languages.
Related
I've been writing C++ a long time and maybe it's because I don't need to do this very often, but I seem to be lacking with regard to operator overloading. I use it from time to time, but never needed to do what I wanted to do recently and found it somewhat problematic.
class foo
{
public:
static const size_t ARRAY_SIZE = 100000;
uint8_t& operator[](const size_t& index) { return my_array[index >> 3]; }
// problematic equality operator
bool operator==(const size_t& index) const { return my_array[index >> 3] & (1 << (index & 7)); }
//
// Need an assignment operator to do:
// my_array[index >> 3] |= 1 << (index & 7);
// ^------------------^ might not needed as it's returned from [] operator
private:
std::array<uint8_t, (ARRAY_SIZE >> 3) + ((ARRAY_SIZE & 7) ? 1 : 0)> my_array;
};
Now as you can see from the above, what is being done here is to take a size_t number and store it in it's relative bit position. So, 5 for instance would be stored in bit 4 of byte 0 and 9 would be stored in bit 1 of byte 1 in the array etc.
Now the subscript operator works fine and returns the correct byte from the array, but that left the problem of things like this:
if (foo[n]) // where n is a size_t integer representing a bit position
It then dawned on me that the above is an abbreviated form of:
if (foo[n] == true)
and so that led to me writing the above equality operator, but for some reason I don't understand, the operator isn't called. I thought it would have been called following the subscript operator, or is it not called because it's not an object of type foo anymore? What's the best way to fix this? Is it to write an external operator== and make it a friend of foo?
Oh and some pointers regarding the construction of the assignment operator would be appreciated too. Thanks very much...
EDIT:
Thanks for all the help people. I do think it's incredibly harsh to get downvoted for asking a question about something I didn't quite understand. It's not like it was a stupid question or anything and if you re-read my original question properly, I did actually question that foo might not be the correct type after the subscript operator, that a few of you have pointed out. Anyway, here's a bit more context. I haven't had chance to properly study all the great replies...
I did originally write the operator like this, which did actually return the correct bit from the array. Something someone has already pointed out.
bool operator[](const size_t index) const { return my_array[index >> 3] & (1 << (index & 7)); }
What I then had a problem with was setting the bits in the array:
foo f;
if (f[3]) // this is fine
But doing something like:
f[6] = true;
I guess what I was hoping for was a more elegant way of doing this than writing the following:-
class Foo
{
public:
static const size_t MAX_LIST_SIZE = 100000;
bool get(const size_t index) const { return my_array[index >> 3] & (1 << (index & 7)); }
void set(const size_t index) { my_array[index >> 3] |= 1 << (index & 7); }
private:
std::array<uint8_t, ((MAX_LIST_SIZE >> 3) + ((MAX_LIST_SIZE & 7) ? 1 : 0))> my_array;
}
and then using the class like this:
Foo f
f.set(10);
if (f.get(10))
...
I just thought it would be easier to overload the operators, but from the look of it, it seems more cumbersome. (Oh and someone asked why I used uint8_t rather than bool, well this is because on this particular platform, bool is actually 32bits!)
Here we have several deep-ish misunderstandings.
Now the subscript operator works fine and returns the correct byte
from the array, but that left the problem of things like this:
if (foo[n]) // where n is a size_t integer representing a bit position
Your problem here is not the if per se; it's that you are returning the wrong thing. If you are building a packed bit set, your operator[] should just return the value of the bit at the requested position. So:
bool operator[](size_t index) { return (my_array[index >> 3]) & (1<<(index&7)); }
and here your if, as well as any other operation involving your operator[], will work as expected.
It then dawned on me that the above is an abbreviated form of:
if (foo[n] == true)
It is not. if evaluates the expression insides the parentheses, and (essentially) casts it to a boolean; if the result is true, it executes the branch, otherwise it does not.
and so that led to me writing the above equality operator, but for some reason I don't understand, the operator isn't called.
The operator isn't called because:
as explained above, the operator== is never involved in if (foo[n]);
even if you explicitly wrote if (foo[n]==true), your operator wouldn't be invoked, because once your operator[] returns, foo is no longer involved.
Think about it: even in your "original" operator[] you return a reference to uint8_t. The statement:
if (a[n] == true)
(with a being of type foo)
is effectively the same as:
uint8_t &temp = a[n];
if (temp == true)
Now, in the expression temp == true the type of a is never mentioned - there's only temp, which is an uint8_t&, independently of how it was ever obtained, and true, a bool literal. Your operator== would be considered if you were comparing a with a size_t, but that would make no sense.
Finally, about your comment:
// Need an assignment operator to do:
// my_array[index >> 3] |= 1 << (index & 7);
// ^------------------^ might not needed as it's returned from [] operator
this, again, won't work for the exact same reason - you need an operator overload to work on the return value of operator[], not on the foo class itself.
This is generally accomplished by having operator[] return not the value itself, but a proxy object, which remembers its parent and the requested index, and provides its own operator== and operator= that perform what you were trying to put straight in the foo class (along with extra operators that make it possible to it to pass for a reference to a boolean).
Something like:
struct PackedBitVector {
static const size_t ARRAY_SIZE = 100000;
struct ElementProxy {
PackedBitVector &parent;
size_t idx;
operator bool() const { return parent.data[idx>>3] & (1<<(idx&7)) }
bool operator==(bool other) const { return bool(*this) == other; }
bool operator!=(bool other) const { return !(*this == other); }
ElementProxy &operator=(bool other) {
if(other) parent.data[idx>>3] |= 1<<(idx&7);
else parent.data[idx>>3] &= ~(1<<(idx&7));
return *this;
}
}:
ElementProxy operator[](size_t index) { return ElementProxy{*this, index}; }
private:
std::array<uint8_t, (ARRAY_SIZE >> 3) + ((ARRAY_SIZE & 7) ? 1 : 0)> data;
};
To make this work in general you'd have to add a full bucket of other operators, so that this proxy object could credibly pass as a reference to a bool, which is what std::vector<bool> does.
About this, from your remark about bool being 32 bit wide on your platform you seem not to know that std::vector<bool> already sports this "packed bit array" space optimization, so you could directly use it, without reimplementing a broken version of the real thing.
For the first time I've written a class that is supposed to be usable as a key type for std::map<>. I've overloaded copy constructor, assignment, and operator < as suggested in other questions on SO. But for some reason it crashes when I'm trying to insert using operator []. This class is meant to hold a buffer of binary data whose length is indicated by the member m_nLen.
Here is the code :
class SomeKeyClass
{
public:
unsigned char m_buffer[ SOME_LENGTH_CONSTANT ];
size_t m_nLen;
public:
inline SomeKeyClass( const unsigned char * data, size_t nLen )
{
m_nLen = min( SOME_LENGTH_CONSTANT, nLen );
memcpy( m_buffer, data, m_nLen );
}
inline SomeKeyClass( const SomeKeyClass& oKey )
{
*this = oKey;
}
inline bool operator < ( const SomeKeyClass& oKey ) const
{
return memcmp( m_buffer, oKey.m_buffer, min( m_nLen, oKey.m_nLen ) ) < 0;
}
inline SomeKeyClass & operator = ( const SomeKeyClass& oKey )
{
memcpy( m_buffer, oKey.m_buffer, oKey.m_nLen );
return *this;
}
};
Is there anything wrong with this class? Could I use std::string<unsigned char> for using binary data as keys instead?
The issue is that you were not setting the m_nLen member in the copy constructor or the assignment operator. Thus whenever you use the object that has the uninitialized or wrong m_nLen value, things may go wrong leading to possible crashes (in general, undefined behavior).
When implementing a user-defined copy constructor and assignment operator, you should strive to make sure that what comes out at the end is an actual copy of the object in question (reference counted objects are a special case, but it still implies that a copy is being done). Otherwise, programs that produce incomplete or wrong copies of the object are very fragile, and an awful burden to debug.
See Paul McKenzie's answer for the reason it crashes.
Is there anything wrong with this class ?
Yes, your operator< is broken.
Consider the case where you have one key "abc" and another key "abcd", your less-than operator will say they are equivalent, because you only test the first 3 characters.
A correct implementation needs to compare the lengths when memcmp says they are equal, because the memcmp call doesn't necessarily compare the full strings:
bool operator<(const SomeKeyClass& oKey) const
{
const std::size_t len = std::min(m_nLen, oKey.m_nLen);
if (len > 0)
{
const int cmp = memcmp(m_buffer, oKey.m_buffer, len);
if (cmp != 0)
return cmp < 0;
}
return m_nLen < oKey.m_nLen;
}
I want to declare a local variable in the brackets of an if statement.
For example.
if((char c = getc(stdin)) == 0x01)//This is not OK with g++.
{
ungetc(c, stdin);
}
What I want is, to see if the character is the one I want.
To say it commonly, I want to use the variable(char c) both in the line of if and the body of if, but not outside the if.
But g++(GCC 4.8.1) says expected primary-expression before 'char'.
I wonder if there's a way to do that, because I don't want something like
char c = getc(stdin);
if(c == 0x01)
{
bla...
}
If it's the namespace pollution you are worrying about you can always define the if statement within a block:
{
char c = getc(stdin);
if(c == 0x01)
{
// ...
}
}
So that c will only last until the end of the block is reached.
I didn't know how to create a variable and test its value with an if until after seeing some of the posted solutions. However, you could use switch. This would allow you to react to additional values (perhaps EOF):
switch (int c = getc(stdin)) {
case 0x01: ungetc(c, stdin); break;
case EOF: // ...handle EOF
default: break;
}
You could always place the if statement in an inlined function instead, and the code will look a little cleaner. If you really want the source code right at that location, but without creating a new scope around an if with a new variable, then perhaps a lambda would be acceptable to you.
[](int c){ if (c == 0x01) ungetc(c, stdin); }(getc(stdin));
Since you are only comparing against one valuem your particular problem does not require a variable at all, so you can simply do:
if (getc(stdin) == 0x01) {
char c = 0x01;
ungetc(c, stdin); //or bla...
}
If you are wanting to compare against a set of values, then the switch suggestion is the better option.
Jerry Coffin's solution looks appealing, but it really boils down to:
if (int c = (getc(stdin) == 0x01)) //...
This is probably not what you really wanted, as it does not generalize well if you want to compare to a value different from 0x01.
Potatoswatter's solution seems closer to what you want, but perhaps it would be nicer to pull the type out into a standalone class:
template <typename T>
class SetAndTest {
const T test_;
T set_;
public:
SetAndTest (T s = T(), T t = T()) : set_(s), test_(t) {}
operator bool () { return set_ == test_; }
operator bool () const { return set_ == test_; }
operator T & () { return set_; }
operator T () const { return set_; }
};
//...
if (auto c = SetAndTest<int>(getc(stdin), 0x01)) {
ungetc(c, stdin); //or bla...
}
You can define the variable inside the if statement just fine. For example, this should compile:
if (int ch = getchar())
;
The problem is that the type (e.g., int) must follow immediately after the opening parenthesis. The extra parenthesis you have is what's causing compilation to fail. So, if you really want to do this, you'll need to get a little clever and use something like this:
if (char ch = 0 || ((ch = getchar()) == 0x1))
This lets you get the creation and initialization of ch done, then after that part of the expression is complete, put in the parentheses around the ch=getchar() to override the precedence of assignment vs. comparison.
Note that && and || do short-circuit evaluation, so you need to be careful with your initialization. You can use either:
if (char ch = 0 || ...
...or:
if (char ch = 1 && ...
...but if you try to use if (ch = 1 || ... or if (ch = 0 && ..., the short-circuit evaluation will keep the right operand (the part you really care about) from being evaluated at all.
Now the caveat: while I'm reasonably certain this code fits the standard's requirements, and most (all?) current compilers will accept it, it's likely to cause most programmers reading the code some serious head-scratching figuring out what you've done, and why. I'd be extremely hesitant (at best) about using this "technique" in real code.
Edit: It's been pointed out that the result from this may be even more misleading than some initially expect, so I'll try to clarify the situation. What happens is that a value is read from input. That value is assigned to ch and compared to 0x1. So far so good. After that, the result of the comparison (converted to an integer, so either 0 or 1) will be assigned to ch. I believe it has sufficient sequence points that the result is defined behavior. But it's probably not what you, or anybody, want -- thus the advice that you probably don't want to use this, and the mention that it would probably leave most programmers scratching their heads, wondering what you were trying to do. In the very specific case of comparing to 0x1, the value of ch inside the if statement will be 1, but it's more or less a coincidence. If you were comparing to 0x2, the value of ch inside the if would still be 1, not 2.
I was wondering if one is inefficient over the other (two codes below)?
if ( abc & myType == myType )
{
if (myValue)
{
// do something
}
}
OR
if ( (abc & myType) && myValue )
{
// do something
}
They are not equivalent, a "corrected" second one would be
if ( (abc & myType == myType) && myValue )
{
// do something
}
In this case, any decent compiler will emit the same code for both.
Also, it's almost never sensible to do this kind of micro-optimization - you waste time around a difference that will be at most of one or two assembly instruction, maybe even in a code path that isn't critical. Here, where there's no real difference in performance, the real optimization to do is towards clarity of your code.
Real optimization is about not caring about these micro-differences (which are probably already taken of by the compiler), and instead profiling the code to find the real bottlenecks.
A few others have pointed out that the two are not equivalent for this reason:
if (abc & myType == myType )
{
if (myValue) {}
}
// OR
if ( (abc & myType) && myValue ) // missing myType == myType
{}
However there is a second reason the two are not equivalent: the == operator has higher precedence than the & operator (see this link). Your first expression therefore evaluates as follows:
if (abc & myType == myType) // Evaluates to (abc & true)
{
if (myValue) {}
}
You probably intended this:
if ((abc & myType) == myType) // Now the bitwise and happens before
// the comparison is made
{
if (myValue) {}
}
To avoid exactly this kind of bug, I always use parentheses to enforce precedence any time there is any possibility of ambiguity from a human's perspective (even though the compiler will never find it ambiguous), on the assumption that the reader has no clue what the actual precedences are. This has the added benefit of making the code easier to read.
For a project I have to implement a bitset class. My code thus far is:
Header File
#ifndef BITSET_H_
#define BITSET_H_
#include <string>
#include <cmath>
using namespace std;
// Container class to hold and manipulate bitsets
class Bitset {
public:
Bitset();
Bitset(const string);
~Bitset();
// Returns the size of the bitset
int size();
// Sets a bitset equal to the specified value
void operator= (const string);
// Accesses a specific bit from the bitset
bool operator[] (const int) const;
private:
unsigned char *bitset;
int set_size;
// Sets a bitset equal to the specified value
void assign(const string);
};
#endif /* BITSET_H_ */
Source File
#include "bitset.h"
Bitset::Bitset() {
bitset = NULL;
}
Bitset::Bitset(const string value) {
bitset = NULL;
assign(value);
}
Bitset::~Bitset() {
if (bitset != NULL) {
delete[] bitset;
}
}
int Bitset::size() {
return set_size;
}
void Bitset::operator= (const string value) {
assign(value);
}
bool Bitset::operator[] (const int index) const {
int offset;
if (index >= set_size) {
return false;
}
offset = (int) index/sizeof(unsigned char);
return (bitset[offset] >> (index - offset*sizeof(unsigned char))) & 1;
}
void Bitset::assign(const string value) {
int i, offset;
if (bitset != NULL) {
delete[] bitset;
}
bitset = new unsigned char[(int) ceil(value.length()/sizeof(unsigned char))];
for (i = 0; i < value.length(); i++) {
offset = (int) i/sizeof(unsigned char);
if (value[i] == '1') {
bitset[offset] |= (1 << (i - offset*sizeof(unsigned char)));
} else {
bitset[offset] &= ~(1 << (i - offset*sizeof(unsigned char)));
}
}
set_size = value.length();
}
My problem is my delete statements in both the deconstructor and assign method core dump. Is it not necessary to deallocate this memory? From what I've read so far it's always necessary to use the delete command whenever you call new.
EDIT: I've changed the code above to reflect one of the fixes. I added bitset = NULL in the constructor. This fixed the core dump in the assign method however I'm still getting errors in the deconstructor.
I think you should initialize bitset to NULL in your second constructor.
Why?
Because a pointer variable won't necessarily be initialized to NULL. So you may be trying to delete[] some random memory address when you use that second constructor.
So you should have:
Bitset::Bitset(const string value) : bitset(NULL)
{
assign(value);
}
Most likely you're copying a Bitset somewhere. You have not defined a copy constructor, not a copy assignment operator. The result of copying is then that you have two instances who both think they should deallocate the dynamically allocated array when they finish.
This is known as the Rule of Three: if you define any of destructor, copy constructor or copy assignment operator, then chances are that you'll need to define all three.
Now, about your code:
#include "bitset.h"
OK.
Bitset::Bitset() {
bitset = NULL;
}
(1) You didn't include a header that guaranteed defines NULL.
(2) you're not initializing the member set_size, so the check in the index operator may/will be using an indeterminate value, with Undefined Behavior.
(3) generally prefer to use initializer list rather than assignment (this avoids e.g. doing default construction followed by assignment).
Bitset::Bitset(const string value) {
bitset = NULL;
assign(value);
}
(4) Generally it's not a good idea to express construction in terms of assignment. Instead, express assignment in terms of construction.
Bitset::~Bitset() {
if (bitset != NULL) {
delete[] bitset;
}
}
(5) The check for NULL is unnecessary; you can safely delete a nullpointer.
int Bitset::size() {
return set_size;
}
(6) Uh, well, set_size was the member that wasn't initialized… Also, this member function should be const.
void Bitset::operator= (const string value) {
assign(value);
}
(7) An assignment operator should in general return a reference to the assigned-to object. That's just a convention, but it's what users of your class expect.
(8) Pass an in-argument by value or by reference to const. Generally, for built-in types choose by-value and for other types, such as std::string, choose reference to const. That is, the formal argument should better be string const& value.
bool Bitset::operator[] (const int index) const {
int offset;
if (index >= set_size) {
return false;
}
offset = (int) index/sizeof(unsigned char);
return (bitset[offset] >> (index - offset*sizeof(unsigned char))) & 1;
}
(9) First, again, the uninitialized set_size member.
(10) Then, note that sizeof(unsigned char) is 1 by definition. You probably want to use CHAR_BIT from <limits.h> here. Or just use 8 unless you plan on supporting Unisys computers (9-bit byte) or perhaps a Texas Instruments digital signal processor (16-bit byte).
void Bitset::assign(const string value) {
int i, offset;
if (bitset != NULL) {
delete[] bitset;
}
(11) The check for NULL is unnecessary.
bitset = new unsigned char[(int) ceil(value.length()/sizeof(unsigned char))];
(12) As already mentioned, sizeof(char) is 1 by definition.
(13) The division has integer arguments and so is an integer division, not a floating point division. Presumably what you want is the trick (a+b-1)/b?
for (i = 0; i < value.length(); i++) {
(14) Style: declare a variable as close to its first use as practically possible. Here it means declare the loop counter i directly in the loop head, like this: for( int i = 0, ....
offset = (int) i/sizeof(unsigned char);
(14) And ditto for offset. But for this variable you're not planning on changing its value, so also declare it const.
if (value[i] == '1') {
bitset[offset] |= (1 << (i - offset*sizeof(unsigned char)));
} else {
bitset[offset] &= ~(1 << (i - offset*sizeof(unsigned char)));
}
(15) Better rethink those shift operations!
}
set_size = value.length();
}
Cheers & hth.,
Make sure that the allocation size isn't zero, I suspect that's what's going on here, and that you're just writing to unallocated garbage memory. Running under valgrind will catch this too.