Reset an element in a circular buffer - arrays

I was asked to implement a circular buffer that takes an unspecified type in C++. I assume the generic type to be of primitive type. (or should it consider non-primitive types?) For the buffer, I am using a basic array, e.g. T[] with new and delete to initialize and destroy it.
I have implemented the buffer class and tested it on integers with the expected output. But it does not work on std::string. The problem is that, when I pop the buffer, I clear the element by setting it to zero, and the compiler complains that doing so is ambiguous. As such, I need a generic way to clear an element, and I thought the std::array might support this feature, but I cannot find it in the documentation.
Is there a generic way to clear an element in a std::array or basic array, or is std::allocator my only option? Or, if I am completely in the wrong direction, How should I implement the pop method to reset the first element and increment the front index to that of the next element?
Thanks in advance!
In case it helps, below is my related code:
template<class T> T CircularBuffer<T>::pop_front()
{
if (_size == 0)
return 0;
T value = buffer[_front];
buffer[_front] = 0;
if (--_size == 0)
{
_front = -1;
_back = -1;
}
else
{
_front = (_front + 1) % _capacity;
}
return value;
}

In a circular buffer you do not really remove elements from memory, otherwise as Jagannath pointed out std::deque is your option. You more like "reset" the elements that have been popped.
buffer[_front] = 0;
means "assign 0 to a T". There are two methods that do that for T = std::string which explains the ambiguity. A bit simplified they look like this:
std::string std::string::operator=(char c);
std::string std::string::operator=(const char *cPtr);
I guess you don't want any of this, so my choice would be (as T.C. wrote):
buffer[_front] = T();
Additionally (and for a very similar reason)
if (_size == 0)
return 0;
is also a problem since it will crash, watch this:
std::string a = circularBuffer.pop_front(); // crashes on empty buffer
You could return T() here but the cleaner way would certainly be throwing an std::out_of_range exception.

One way you could do this, is by treating the memory as raw memory, and using placement new, and manual destructor call.
It could look something like this:
void push(const T& val)
{
new ( data + sizeof(T)*idx++ ) T { val };
}
void pop()
{
( (T*) (data + sizeof(T)*--idx) ) -> ~T();
}

Related

Is this code dereferencing a pointer or doing something else?

I've never seen this kind of thing before - I'm a little new to shared_ptr - is this a typical operation with a shared pointer, or is someone doing something a little fancy here? It doesn't seem like a dereference - it looks more like someone's trying to make sure the operator->() is defined...
I've done a google/duckduckgo on this in as many ways as I can think of, can't find any good examples online.
Thanks.
void fn(std::shared_ptr<int> data){
if(data.operator->() == NULL){
return; //this is an error
}
....//rest of function, doesn't matter
}
By
T* operator->() const noexcept;
you are accessing internal pointer of shared_ptr. If it is not NULL you can read data pointed by this pointer. To do it you must use:
T& operator*() const noexcept;
So when you want to check if shared_ptr points some data and read it, you could write:
void fn(std::shared_ptr<int> data) {
if(data.operator->() == NULL) // dereference pointer
return; //this is an error
int value = data.operator*(); // dereference data pointed by pointer
}
The code above is rather fancy way of using shared_ptr instances. Instead of calling operators like member functions - obj.operator #() you can use shorter form by applying #obj:
// this code does the same thing as above
void fn2(std::shared_ptr<int> data)
{
if(!data)
return; //this is an error
int value = *data;
std::cout << value << std::endl;
}
For more details, see reference.

LabVIEW Call Library Function yielding array of strings

I need to interface C code to LabVIEW, and my C function needs to give back a two dimensional array of strings. I would rather not be forced to predetermine the size of the array in advance. So I want to know, what is the right data format to use (handle to array of C string pointers? Handle to array of string handles?), how to properly do the allocation, and whether it is better to use an array parameter or a return type. The dialog provided for Call Library Function Node only supports arrays of numeric types, so I'm a little bit lost on how to structure this.
You need the LabVIEW Code Interface Reference Manual to figure this stuff out.
You are writing a C function that will return a 2D array of strings to LabVIEW. That means you need to be returning LabVIEW's data structure and using LabVIEW's memory allocator. Include "extcode.h" in your C file (ships with LabVIEW). Then create the following C code:
#include "extcode.h"
struct String2DArrayBlock {
int32 dimensionSize1;
int32 dimensionSize2;
LStrHandle stringArray[1]; // Yes, this is intentional. Do not use LStrHandle* because that syntax changes the memory allocation. Old-school C code. LabVIEW's own C++ code has wrappers for managing this with more type safety.
};
typedef String2DArrayBlock** String2DArrayHandle;
MgErr GenerateMyStrings(String2DArrayHandle *ptrToHandle) {
if (!ptrToHandle)
return mgArgErr; // Gotta pass a location for us to allocate.
if (*ptrToHandle) {
// This handle is already allocated. I'm not going to walk you through all the code needed to deallocate.
return mgArgErr;
}
const int32 dimSize1 = ComputeHeight(); // This is your function... whereever your data is coming from.
const int32 dimSize2 = ComputeWidth(); // Same here.
const int32 numberOfElements = dimSize1 * dimSize2;
if (numberOfElements == 0) {
return mgNoErr; // Done. NULL means empty array, and the handle is already NULL.
}
// DSNewHClr allocates the block and flood fills it with all zeros.
*ptrToHandle = (String2DArrayHandle)DSNewHClr(sizeof(String2DArrayBlock) + ((numberOfElements - 1) * sizeof(LStrHandle))); // -1 because the sizeof block has 1 element.
if (!*ptrToHandle)
return mFullErr; // Out of memory
(**ptrToHandle)->dimensionSize1 = dimSize1;
(**ptrToHandle)->dimensionSize2 = dimSize2;
LStrHandle *current = (**ptrToHandle)->stringArray;
for (int32 i = 0; i < numberOfElements; ++i, ++current) {
std::string myCurrentString = GetMyCurrentString(i); // You write this however you look up the individual strings.
if (myCurrentString.empty())
continue; // NULL means empty string
*current = (LStrHandle)DSNewHClr(sizeof(LStr)); // Allocates a zero-length LStrHandle.
if (!*current)
return mFullErr; // The array will be partially filled, but it is in a safe state for early return.
MgErr err = LStrPrintf(*current, (CStr)"%s", myCurrentString.c_str());
if (err)
return err; // The array will be partially filled, but it is in a safe state for early return.
}
return mgNoErr;
}
Compile your code against the LabVIEW run-time engine (lvrt.dll).
In your G code, drop a Call Library Node, add a parameter that is "Adapt to type" and "Pointers to Handles", and wire it with an empty 2D array. And you're done.

Counting of objects in linked list

I have a linked list and I need to count only some of records according some criteria. I have got this code.
int count_records() {
int number = 0;
RECORD *re;
char criteria[20];
for (re = first; re != NULL; re = re->next) {
criteria = (re->criteria);
if(criteria=="something")
number++;
}
return number; }
Structure of linked list is this:
typedef struct record {
char criteria[20];
struct record *next;
} RECORD;
Problem is that it gives me this error on line criteria = (re->criteria); Error: Invalid array assignment
Any ideas?
Thanks.
You have arrays of char´s. To copy or compare an array, you´ll need to copy/compare each element separately instead of using = and == on the whole array in one go.
And instead of making a loop, you can use strcpy and strcmp in this case:
strcpy(criteria, re->criteria);
if(!strcmp(criteria, "something"))
By the way, this is more C than C++. If you want a C++-like solution, see std::string (then you can work with = and == too)
Indeed, you can't copy arrays using =. Neither can you compare them using ==. They are quite strange, unfriendly things, which need a certain amount of care to use.
If you want to use arrays, you can use the C library to compare them:
if (std::strcmp(re->criteria, "something") == 0)
Since this is C++, you might prefer to use std::string to represent strings; then it's just
if (re->criteria == "something")
and you can copy it with = if you need to (although you don't need to here).
In C++ you can and should use std::string for handling strings. You can find the reference (here).
Just define criteria as std::string criteria; instead of char criteria[20];.
Don't forget to add #include <string> to the include section.
You need to use memcpy in order to copy arrays, but be careful using memcpy when exposed on a public interface. I think there was a recent security issue involving this...
I think that you may wish to pass in the criterion to your count_records() function. I'd render it like this:
int count_records(RECORD *first, const char *criterion) {
int count = 0;
RECORD *re;
for (re = first; re != NULL; re = re->next) {
/* add to count if the strings match */
if(!strcmp(criterion, re->criteria))
count++;
}
return count;
}
Note that it also doesn't rely on first being a global variable which makes the code more reliable and easier to understand.
If you want to copy a char array into another, you need to use strcpy. For example:
// will copy from array1 to array2
strcpy(array2, array1);
You can't directly do array1 = array2. Because in this case you would manipulate the adresses (char *) of the arrays and not their values.
In addition, in order to compare a char array to another, use strcmp instead:
if(strcmp(criteria, "something") == 0)
P.S.: Since you're using C++, std::string is your friend, which you can do assignment using = and comparison using ==.
Dealing with strings in C is a royal pain when you are starting out with the language. You can checkout an online tutorial to get you started.
In the mean time, you can change your code to:
for (re = first; re != NULL; re = re->next) {
if (strcmp(re->criteria, "something) == 0)
number++;
}
You don't need to copy re->criteria to a local variable.

Arguments against static int pointer

I'm about to debug someone else's code and I stumbled across a certain 'way' of handling with global arrays which I consider deeply bad, but the one who first used it swears to it.
I need to find arguments against it.
Here is the code written simplified (this is not the original code, just an abstracted version)
So my question: which arguments would you bring against (or maybe some code which brings down this method) this?
int test(int i, int v, int type, int** t)
{
static int *teeest;
int result = 0;
switch(type)
{
case (1):
{
int testarr[i];
teeest = testarr;
}
break;
case (2):
result = teeest[i];
break;
case (3):
teeest[i] = v;
break;
}
if (t != NULL)
{
*t = teeest;
}
return result;
}
int main()
{
int *te = (int*)1;
test(5, 0, 1, &te);
printf("%p\n", te);
int i=0;
for(;i<5;i++)
{
test(i, i, 3, NULL);
printf("Value: %d\n", test(i,0,2, NULL));
}
return 0;
}
local variables are dead after the block they declared in, so this code is undefined behavior. Like every accessing random address, it may work, but it also may not work.
Note that if you use malloc instead of int testarr[i], (and worry to free the previous array, and to initialize teeest), it will be correct. the problems of this code have nothing about static pointers.
This is really bad. Just because the pointer is static doesn't mean the data it points to will be around. For example, testarr disappears when the function exits and the returned pointer, if used, might cause dragons to appear.
It seems to me the big downfall of this style is that you are hiding the fact that you are accessing a locally declared array which is on the stack. Then you persist a pointer to your stack which will persist through calls, which will have different stacks each call.
Another thing I was thinking about is that you have hidden from the developer what the data structure is. Indexing an array is a normal operation. Indexing a pointer makes the developer acknowledge it is an array and not a more complex data type. This also adds confusion to bounds checking.
Another thing is, that all disadvantages of global variables apply directly. The code is not reentrant, and hard to make thread-safe (if that's a concern).

Rationale for Passing Pointer as Function Parameter and Returning it in C

I'm examining the source code (written in C) of bkhive -- a utility for dumping the SysKey bootkey from a Windows NT/2K/XP system hive -- and would like to know if there is any rationale for something the original author did: passing a pointer to a struct into a function and then returning the same pointer. Here is the relevant source code:
In main() there is a call that looks like this:
struct hive h;
char *root_key;
// Do some stuff to init
_RegGetRootKey(&h, &root_key)
Which calls:
int _RegGetRootKey(struct hive *h, char **root_key)
{
nk_hdr *n;
n = (nk_hdr*) malloc(sizeof(nk_hdr));
/* ************************************************
* RELEVANT FUNCTION CALL
* Why pass n as a parameter and use return value?
* ************************************************/
n = read_nk(n, h, 0x1020);
if (n->id == NK_ID && n->type == NK_ROOT)
{
*root_key = (char *) malloc(n->name_len + 1);
strncpy(*root_key, n->key_name, n->name_len);
(*root_key)[n->name_len] = 0;
free(n);
return 0;
}
free(n);
return -1;
}
Which calls:
nk_hdr* read_nk(nk_hdr *nk, struct hive *h, int offset)
{
memcpy(nk, h->base + offset + 4, sizeof(nk_hdr));
nk->key_name = (h->base + offset + 4 + 76);
return nk;
}
So, what is the purpose of passing the struct pointer and then returning it? Couldn't the function return nothing and use n after the function call?
The main benefit of this convention is to allow for simpler concatenation of function calls. If you want to use the return of one function as a parameter to another function, having it return the pointer can enable you to write the statement in a single line. Thus, instead of writing something like this:
foo(myPtr);
bar(myPtr);
You can do this:
bar(foo(myPtr));
The specific code you show doesn't use this, but this is a convention used in many C functions, and I guess the author of the code is used to this by now.
In this exact case, there doesn't appear to be much use for it. But in general, there are two reasons I've done the same thing in the past:
One is where the function might reallocate the item pointed at, in which case the return could be the same pointer that was passed, or could be a replacement for it with a different value.
Another, even when the pointer won't change, is that it allows the return from the function to be used immediately to access the pointed-to item, in constructs like somefunc(item)->member = 5; among others. It lets you drop the function call into another expression that needs the same pointer afterward.
It could also be just to make the function's use consistent with others in the API, some of which may have a reason to do this.
This allows you to pass the object by reference, and then get a handle (i.e., pointer) to the updated value on return ... it also allows you to pass back a NULL if something goes wrong, so that you know the state of the object that you passed in by reference is not good anymore. For instance:
struct my_struct* pass_by_ref = malloc(sizeof(my_struct));
//...some more code
if (foo(pass_by_ref) == NULL)
{
free(pass_by_ref); //pass_by_ref is no longer any good ...
perror();
}

Resources