class mapInfo
{
public:
mapInfo();
~mapInfo();
public:
int dataType_m;
private:
int *frequency;
};
//constructor is defined here.
mapInfo::mapInfo() :
dataType_m(0),
frequency(NULL)
{
}
//destructor is defined here
mapInfo::~mapInfo()
{
free(frequency);
frequency = NULL;
}
Result_t Maps::add(mapInfo &mapInfo_r)
{
if (maps_mp == NULL)
{
numMaps_m = 1;
maps_mp = (mapInfo *) calloc(1, sizeof(mapInfo));
}
else
{
numMaps_m++;
maps_mp = (mapInfo *) realloc(maps_mp, numMaps_m*sizeof(mapInfo));
}
maps_mp[numMaps_m-1] = mapInfo_r; // Default copy constructor
return 1;
}
While compiling with gcc8, getting the following compilation error. It looks like defining the destructor like above giving the compilation error for gcc8.
How to resolve this?
error: 'void* realloc(void*, size_t)' moving an object of non-trivially copyable type 'class xyyz::mapInfo'; use 'new' and 'delete' instead [-Werror=class-memaccess].
That’s simply not proper C++. Rewrite your code as follows (I’m guessing here with regards to the type of frequency, but definitely don’t use free on it):
#include <vector>
class map_info
{
public:
map_info();
private:
int data_type;
std::vector<int> frequency;
};
std::vector<map_info> maps_mp;
map_info::map_info() : data_type(0), frequency() {}
// …
void maps::add(map_info& map_info)
{
maps_mp.push_back(map_info);
}
maps_mp = (mapInfo *) realloc(maps_mp, numMaps_m*sizeof(mapInfo));
This is not sensible. You can't just move an object from one aree of memory to another if that object is non-trivial.
For example, consider a string object that keeps a pointer to the string. It could look like this:
class MyString
{
char* inner_ptr;
char buf[64];
...
};
And it might have a constructor like this:
MyString::MyString (const char* j)
{
if (strlen(j) < 64)
inner_ptr = buf;
else
inner_ptr = malloc (strlen(j) + 1);
strcpy(inner_ptr, j);
}
And a destructor like this:
MyString::~MyString()
{
if (buf != inner_ptr)
free (inner_ptr);
}
Now, think about what happens if you call relloc on an array of these. The short strings will still have their inner_ptrs pointing to the old object's buffer, which you just deallocated.
The error message explains this issue reasonable well. It is simply not legal to use realloc to move a non-trivial object. You have to construct a new object because the object needs a chance to handle the change in its address.
In my project I'm making a C class hierarchy similar to, but not the same as Axel-Tobias Schreiner Object-oriented Programming in ansi C see https://www.cs.rit.edu/~ats/books/ooc.pdf. for example.
I'm initializing my object a little bit different than Axel is. I'm running into troubles when I'm passing va_list objects between multiple initializing functions. Say I've an object two, that derives from object one. Then while initializing a two object, I'll need to initialize the one part first, and subsequently initialize the two part.
So I'm having 1 init function that calls the public initializer function with arguments that initialize the one part of the two object and arguments that only initializes the two part that extends one object.
The library I'm creating is quite large, but I've extracted a mini project from it that demonstrates the same issues:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project (var_args
VERSION "0.0"
LANGUAGES C CXX
)
set(HEADERS "init.h")
set(SOURCES init.c program.c)
add_executable(program ${SOURCES} ${HEADERS})
if (NOT MSVC)
target_compile_options(program PRIVATE -W -Wall -Wextra -pedantic)
else()
target_compile_options(program PRIVATE /W4)
endif()
init.h:
typedef struct _one {
int a;
const char* msg;
} one_t;
/* this struct "derives" from struct _one */
typedef struct _two {
one_t parent;
double pi;
double e;
}two_t;
enum status_t {
STATUS_SUCCES,
STATUS_INVALID_ARGUMENT,
STATUS_ERROR
};
enum init_one_flags {
INIT_ONE_A, // 2nd argument should be of type int
INIT_ONE_MSG, // 3rd argument should be const char*
INIT_ONE_FINISHED, // takes no arugment, but rather tell init1 should be finished.
INIT_ONE_SENTINAL // Keep at the last position.
};
enum init_two_flags {
INIT_TWO_PI = INIT_ONE_SENTINAL, // 2nd arugument should be of type double.
INIT_TWO_E, // 2nd argument shoudl be double.
INIT_TWO_FINISHED, // takes no arugment, but rather tell init2 should be finished.
INIT_TWO_SENTINAL, // for init3...
};
#ifdef __cplusplus
extern "C" {
#endif
int init_two(two_t* two, ...);
//void init_one(one_t* one, ...);
#ifdef __cplusplus
}
#endif
init.c:
#include <stdarg.h>
#include "init.h"
static int priv_init1(one_t* one, va_list list)
{
// use default values;
int a = 0;
const char* msg = "";
int selector, ret = STATUS_SUCCES;
while ((selector = va_arg(list, int)) != INIT_ONE_FINISHED) {
switch (selector) {
case INIT_ONE_A:
a = va_arg(list, int);
break;
case INIT_ONE_MSG:
msg = va_arg(list, const char*);
break;
default:
// unknown argument
return STATUS_INVALID_ARGUMENT;
}
}
one->a = a;
one->msg = msg;
return ret;
}
static int priv_init2(two_t* two, va_list list)
{
double pi = 3.1415, e=2.7128;
int selector, ret = STATUS_SUCCES;
ret = priv_init1((one_t*)two, list);
if (ret)
return ret;
while ((selector = va_arg(list, int)) != INIT_TWO_FINISHED) {
switch (selector) {
case INIT_TWO_PI:
pi = va_arg(list, double);
break;
case INIT_TWO_E:
pi = va_arg(list, double);
break;
default:
return STATUS_INVALID_ARGUMENT;
}
}
two->pi = pi;
two->e = e;
return STATUS_SUCCES;
}
int init_two(two_t* two, ...)
{
int ret;
va_list list;
va_start(list, two);
ret = priv_init2(two, list);
va_end(list);
return ret;
}
program.c:
#include <stdio.h>
#include "init.h"
int main() {
int ret;
two_t two;
ret = init_two(
&two,
INIT_ONE_A, 1,
INIT_ONE_MSG, "Hello, world",
INIT_ONE_FINISHED,
INIT_TWO_PI, 2 * 3.1415,
INIT_TWO_FINISHED
);
if (ret) {
fprintf(stderr, "unable to init two...\n");
printf("a=%d\tmsg=%s\tpi=%lf\te%lf\n",
two.parent.a,
two.parent.msg,
two.pi,
two.e
);
return 1;
}
else {
printf("a=%d\tmsg=%s\tpi=%lf\te%lf\n",
two.parent.a,
two.parent.msg,
two.pi,
two.e
);
return 0;
}
}
Now the problem I'm running into is that the behavior of this code is exactly what I expect on Linux with gcc or clang in debug and release builds. Unfortunately the code fails on Windows with visual studio 17.
So the output of the program should be someting like:
a=1 msg=Hello, world pi=6.283000 e2.712800
And that is exactly what I obtain on Linux with gcc (5.4.0-6)
On windows I get:
a=1 msg=Hello, world pi=jiberish here e2=jiberish here.
And the function init_two does return that the function was successful on Linux and that is is not successful on windows. Also I can see that the part of one_t part of two is initialized successfully, whereas the two_t part is not.
I would be very grateful if someone would point out the issue what is going wrong. Is the va_list is passed by reference on Linux, whereas the va_list is passed by value on windows? Are the enum values promoted to int on Linux, whereas they are passed as char on windows?
Finally, I tagged the question as C and C++ because I know the code I demonstrate is C, but I would like it to work with a C++ compiler as well.
The implementation of va_list can differ greatly across compilers.
It's possible, for example, that gcc implements it as a pointer so passing it to another function by value still modifies the underlying structure so that changes in the called function are visible in the calling function, while MSVC implements it as a struct so changes in the calling function are not visible in the caller.
You can get around this by passing a pointer to your initial va_list instance to all the functions that need it. Then the internal state will be consistent in all functions.
// use pointer to va_list
static int priv_init1(one_t* one, va_list *list)
{
// use default values;
int a = 0;
const char* msg = "";
int selector, ret = STATUS_SUCCES;
while ((selector = va_arg(*list, int)) != INIT_ONE_FINISHED) {
switch (selector) {
case INIT_ONE_A:
a = va_arg(*list, int);
break;
case INIT_ONE_MSG:
msg = va_arg(*list, const char*);
break;
default:
// unknown argument
return STATUS_INVALID_ARGUMENT;
}
}
one->a = a;
one->msg = msg;
return ret;
}
// use pointer to va_list
static int priv_init2(two_t* two, va_list *list)
{
double pi = 3.1415, e=2.7128;
int selector, ret = STATUS_SUCCES;
ret = priv_init1((one_t*)two, list);
if (ret)
return ret;
while ((selector = va_arg(*list, int)) != INIT_TWO_FINISHED) {
switch (selector) {
case INIT_TWO_PI:
pi = va_arg(*list, double);
break;
case INIT_TWO_E:
pi = va_arg(*list, double);
break;
default:
return STATUS_INVALID_ARGUMENT;
}
}
two->pi = pi;
two->e = e;
return STATUS_SUCCES;
}
int init_two(two_t* two, ...)
{
int ret;
va_list list;
va_start(list, two);
ret = priv_init2(two, &list); // pass pointer
va_end(list);
return ret;
}
This usage is explicitly mentioned in section 7.16p3 of the C standard:
The type declared is
va_list
which is a complete object type suitable for holding
information needed by the macros va_start , va_arg , va_end , and
va_copy . If access to the varying arguments is desired, the
called function shall declare an object (generally referred to
as ap in this subclause) having type va_list.
The object ap may be passed as an argument to another
function; if that function invokes the va_arg macro with
parameter ap , the value of ap in the calling function is
indeterminate and shall be passed to the va_end macro prior to
any further reference to ap. 253)
253) It is permitted to create a pointer to a va_list and
pass that pointer to another function, in which case the
original function may make further use of the original list after the
other function returns.
This should work with any compiler:
static int priv_init1(one_t* one, va_list* list)
{
// use default values;
int a = 0;
const char* msg = "";
int selector, ret = STATUS_SUCCES;
while ((selector = va_arg(*list, int)) != INIT_ONE_FINISHED) {
switch (selector) {
case INIT_ONE_A:
a = va_arg(*list, int);
break;
case INIT_ONE_MSG:
msg = va_arg(*list, const char*);
break;
default:
// unknown argument
return STATUS_INVALID_ARGUMENT;
}
}
one->a = a;
one->msg = msg;
return ret;
}
static int priv_init2(two_t* two, va_list list)
{
double pi = 3.1415, e=2.7128;
int selector, ret = STATUS_SUCCES;
ret = priv_init1((one_t*)two, &list);
if (ret)
return ret;
while ((selector = va_arg(list, int)) != INIT_TWO_FINISHED) {
switch (selector) {
case INIT_TWO_PI:
pi = va_arg(list, double);
break;
case INIT_TWO_E:
pi = va_arg(list, double);
break;
default:
return STATUS_INVALID_ARGUMENT;
}
}
two->pi = pi;
two->e = e;
return STATUS_SUCCES;
}
Anyway your design that va_list is increased by two diffrent functions looks very fragile. I wouldn't do that.
Also you API design requires specific and complex sequnce of arguments which compilers do not recognize. This is so bug prone that I would not pass this in code review.
Since this looks like XY problem. I recommend creating another question about your X problem (how to design API which does what you need).
As I understand it, the issue revolves around the fact that your implementation of inheritance requires the initialization function for a subclass to call the initialization function(s) of its superclass(es). This is combined with the fact that the user-facing initialization functions are declared as varargs functions. To make this work, the varargs functions serve as front ends for internal functions that accept the variable arguments via single parameters of type va_list.
This can be made to work in standard C, but you must observe some restrictions. Among those:
Your varargs functions must each initialize their va_list via the va_start macro, exactly once.
Your functions may pass objects of type va_list to other functions, but the caller may not afterward use that object unless they can be confident that the called function did not use either va_arg nor va_end on it, or unless they themselves first use va_end and then va_start on it.
Every use of va_start or va_copy must be paired with a corresponding use of va_end on the same va_list
Of course, it is up to you to ensure that the correct data types are specified to each use of va_arg.
You violate the second requirement by passing a va_list from one internal initialization function to another, and then afterward using it.
You should be able to work around this by passing pointers to the va_list and accessing it indirectly, so that all the functions involved use the same object. This will enable the state of the va_list to be shared, so that, for example, the initialization function for the topmost class can effectively consume the arguments intended for it, without its subclasses needing to know their number or types. That would take a form something like this:
static int priv_init1(one_t* one, va_list *list) {
while ((selector = va_arg((*list), int)) != INIT_ONE_FINISHED) {
// ...
}
// ...
return ret;
}
static int priv_init2(two_t* two, va_list *list) {
int ret = priv_init1((one_t*)two, list);
// ...
while ((selector = va_arg((*list), int)) != INIT_TWO_FINISHED) {
// ...
}
// ...
return STATUS_SUCCES;
}
int init_two(two_t* two, ...) {
int ret;
va_list list;
va_start(list, two);
ret = priv_init2(two, &list);
va_end(list);
return ret;
}
I'm getting the error call of overloaded function is ambiguous and I understand it's because the compiler can't differentiate between them, but is there a way to work around this while maintaining the same parameters? I have to use the declarations I've provided below and it's confusing me as to how I can use them both if I met with this error every time.
I've shortened my code to show the constructors that are posing the issue.
ErrorMessage.h
class ErrorMessage {
char* message_; //pointer that holds the address of the message stored in current object
public:
ErrorMessage();
explicit ErrorMessage(const char* errorMessage = nullptr); //receive address of a C-style nullterminate string holding an error message
}
ErrorMessage.cpp
namespace sict {
ErrorMessage::ErrorMessage() {
message_ = nullptr;
}
ErrorMessage::ErrorMessage(const char* errorMessage) {
if(errorMessage == nullptr) {
message_ = nullptr;
}
else {
message(errorMessage);
}
const char* ErrorMessage::message() const {
return message_;
}
}
Just remove the constructor which takes no parameters. The second constructor already does everything the first constructor does.
If it receives a nullptr, it tests it and sets the local variable, if not it continues with its logic. The first constructor is completely superfluous.
Okay so i'm looking at the documentation for pthread_create and I just don't understand at all how to do what I want to do.
I want to call pthread_create which will obv pass in a struct of pthread_t. But the function I pass to it takes in a pointer to a of MyNode*. How would I pass the function as a parameter and pass it "this" as a parameter to that function.
//MyNode field and method in class file
pthread_t myTrd;
static void compute(MyNode* node);
////////////////////////////////////////////////////////////
//Actual code in header file below
static void MyNode::compute(*MyNode node){ //L61
//code
}
void MyNode::run(){ //run function in header file
pthread_create(&(this->thread),NULL,MyNode::compute, this);
}
outcome:
myNode.cpp:61: error: 'static' may not be used when defining (as opposed to declaring) a static data member
myNode.cpp:61: error: 'int MyProjectGraph::MyNode::compute' is not a static member of 'class MyProjectGraph::MyNode'
myNode.cpp:61: error: expected primary-expression before 'node'
myNode.cpp:61: error: expected ',' or ';' before '{' token
myNode.cpp:134: error: expected `}' at end of input
The function passed to pthread_create() should match the prototype:
void *function(void *arg);
If your function does not match that, you have to use brute force and ignorance (and a cast) to make the function pointer acceptable — and then hope that the alternative interface doesn't break anything.
It is far better to make your function match the specification:
void *function(void *arg)
{
MyNode *mnp = (MyNode *)arg;
…
return 0;
}
The return can return some more meaningful value if you have one available, but returning a null (you could probably write nullptr given that you're mainly using C++).
Note that pthread_create() is usually a C function itself and expects C function semantics in the function pointer it is passed.
Having a thread per object isn't really a good way to go. I presume that
since you are calling your object a node, you have a bunch of them
and want to do something to them on a thread.
I typically do the following, which is a classic idiom:
class Worker
{
struct ThreadStr
{
Worker * worker;
// put parameters here
MyNode * node;
};
public:
static void *StaticHandler(void *pvoid)
{
ThreadStr * data = (ThreadStr*)pvoid;
data->worker->Compute(data->node);
delete data;
return NULL;
}
void Compute(MyNode *node)
{
// whatever you want to compute on a node.
}
// start a thread to execute Worker::Compute(MyNode*)
void Run(MyNode *node)
{
ThreadStr * data = new ThreadStr();
data->worker = this;
data->node = node;
pthread_t threadId;
pthread_create(&threadId, NULL, Worker::StaticHandler, data);
}
};
I create the two following objects:
bool Reception::createNProcess()
{
for (int y = 0; y < 3; ++y)
{
Process *pro = new Process; // forks() at construction
Thread *t = new Thread[5];
this->addProcess(pro); // Adds the new process to a vector
if (pro->getPid() == 0)
{
for (int i = 0; i < 5; ++i)
{
pro->addThread(&t[i]); // Adds the new thread to a vector
t[i].startThread();
}
}
}
Where I create 3 processes (that I have encapsulated in Process) and create 5 threads in each of these processes.
But I'm not sure the following line is correct:
Thread *t = new Thread[5];
Because my two functions addProcess and addThread both take a pointer to Process and Thread respectively and yet the compiler asks for a reference to t[i] for addThread and I don't understand why.
void Process::addThread(Thread *t)
{
this->threads_.push_back(t);
}
void Reception::addProcess(Process *p)
{
this->createdPro.push_back(p);
}
createdPro is defined in the Reception class as follows:
std::vector<Process *> createdPro;
and threads_ in the Process class like such:
std::vector<Thread *> threads_;
And the error message (as obvious as it is) is as follows:
error: no matching function for call to ‘Process::addThread(Thread&)’
pro->addThread(t[i]);
process.hpp:29:10: note: candidate: void Process::addThread(Thread*)
void addThread(Thread *);
process.hpp:29:10: note: no known conversion for argument 1 from ‘Thread’ to ‘Thread*’
Even though I defined my Thread as a pointer.
You have defined the member function to take a pointer:
void Process::addThread(Thread *t)
{
...
}
You then invoke this function for &t[i], which is a pointer and should work perfectly:
pro->addThread(&t[i]); // Adds the new thread to a vector
You could also invoke it with t+i and it would still be ok. However your error message tells us something different: the compiler doesn't find a match for pro->addThread(t[i]); (i.e. the & is missing).
Either you made a typo in your question, or you made a typo in your code. Or you have another invocation somewhere where you've forgotten the ampersand: t[i] would of course designate an object (it's equivalent to *(t+i) ) and not a pointer, and cause the error message you have (demo mcve)