I having difficulty saving a pointer argument that my mock receives.
#define SIZE_OF_DATA
typedef struct {
uint32_t someValue1;
uint16_t someValue2;
// other values here
} LargeStruct;
class SomeClass {
public:
// assume sendData is a generic function where data is actually pointer to a LargeStruct
void sendData(const uint8_t* data, const uint16_t size);
}
class MockClass : public SomeClass {
public:
MOCK_METHOD2(sendData, void(const uint8_t*, const uint16_t));
};
I want to save the first argument to sendData (the pointer) and look at the data it points to (it points to a large struct, so I don't want to copy by value):
TEST(SomeFixture, sendData_checkSentDataIsValid) {
MockClass mock;
const uint8_t *pData;
EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA)).WillOnce(SaveArg<0>(&pData));
// do something here that calls sendData()
// hopefully data should point to the same data that was passed in to the method
LargeStruct *ls = (LargeStruct *)pData;
// now verify that the data is ok...
// some expectations here
EXPECT_EQ(SOMEVALUEIWANT, ls->someValue1);
}
However, the data pointed to by pData is wrong - I think I appear to be saving the pointer value into the struct, rather than saving the pointer.
I think the problem lies in the variable I pass to SaveArg, but I can't seem to get it in a version that compiles and gives me the correct answer. Any pointers please?
I just ran into the same situation, and in my case, I had to make sure that the pointer passed into the equivalent of your sendData() function was not pointing to an automatic variable on the stack. Otherwise, by the time you access the pointer, the contents will have changed. I found that less than helpful, so I decided to define a customized alternative to SaveArg like this:
ACTION_TEMPLATE(SaveSomeValue1,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer))
{
const void * data = ::std::tr1::get<k>(args);
const LargeStruct* ls = (const LargeStruct *)data;
*pointer = ls->someValue1;
}
You can then use it like this:
uint32_t someValue1;
EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA))
.WillOnce(SaveSomeValue1<0>(&someValue1));
//...
EXPECT_EQ(SOMEVALUEIWANT, someValue1);
You can create one void pointer as a buffer and save argument inside that buffer. After that you should cast the buffer to your large structure.
TEST(SomeFixture, sendData_checkSentDataIsValid) {
MockClass mock;
LargeStruct *ls;
void *buffer;
EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA))
.WillOnce(SaveArg<0>(&buffer));
// do something here that calls sendData()
ls = static_cast<LargeStruct *>(buffer);
EXPECT_EQ(SOMEVALUEIWANT, ls->someValue1);
}
Related
I have this function callback that receives a param of type T. T has a member function, GetData(), defined as below, which returns data to be used within the callback:
void Callback(T* t) {
int64_t val;
auto data = t->GetData();
memcpy(&val, data, 8);
std::cout << "Value: " << val;
}
// Member of a class T:
char mData[64];
// Member functions of T
const char* GetData() const { return mData; }
void SetData(void* data, uint8_t size) {
if (size > 0) {
memcpy(mData, data, size);
}
}
The above works fine. However, for some reason, I can't seem to pass a 'this' pointer of a class within the data component. This is how the data is copied to the mData member.
// This works
char data[64];
int64_t val = 42;
memcpy(&data, &val, 8);
t->SetData(data, 8);
// For storing 'this', I tried variations of the below.
char data[64];
memcpy(&data, this, 8);
t->SetData(data, 8);
// t->SetData(this, 8);
When I try to store 'this' in the data, and then try to get it back in the callback, I can't seem to get the this pointer's value correctly. I tried variations of the below, including reinterpret_cast and others.
void Callback(T* t) {
TypeOfThis* self;
auto data = t->GetData();
memcpy(&self, data, 8);
// self has bogus values.
}
How can I pass a 'this' pointer correctly, in the case above?
firstly "this" is to be used inside a class. 2ndly: "this" address does not necessarily point to the first data member of the class as there are some admin data subject to the compiler implementation, in other words there may be a few bytes gap between "this" and its first data member.
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
As part of a "message"-class I try to transfer pointers of different types by casting them to void*-pointers and saving them in a wrapper class ("MsgData") that remembers the original type of the pointer.
For example a bool pointer:
bool* data = new bool;
event.wheel.y < 0 ? *data = false : *data = true;
send("all", this, MSG_MOUSE_SCROLL, MsgData(data));
The compatible Constructor of MsgData is called and the variable is saved as a member of my message class:
MsgData(): type_(NULLPTR), data_(nullptr) {} // Null
MsgData(const bool* data): type_(BOOL), data_((void*)data) {} // Bool
MsgData(const std::string* data): type_(STRING_STD), data_((void*)data) {} // std::string
// ... etc.
I can cast the pointers back and use them without any errors but when I try to delete them the program crashes:
~MsgData() {
switch (type_) {
case (BOOL):
if ((bool*)data_)
delete (bool*)data_;
break;
// ... etc.
}
}
The bool pointer is just an example and the same happens with all other types and classes too.
The program crashes only when I try to delete the pointer. Casting them back to their original type and using them is not a problem.
I researched the problem and found similar question like this one on StackOverflow but while it seems to be considered bad style to cast a pointer to void* and back I cannot find the reason why the program crashes.
Well, a better solution to the problem is to use boost::variant (or std::variant). Once you start using that, all the headache of deleting and managing type and data will go automatically. You're not the first to face of a problem of this kind; many others have faced it, and the solution is available in the form of boost::variant or std::variant.
Anyway, since you're developing a solution yourself, here is my advise: construct an appropriate deleter in the constructor itself .. or whenever you know what type of data your class is going to hold:
MsgData()
: type_(NULLPTR), data_(nullptr) {}
MsgData(const bool* data)
: type_(BOOL), data_((void*)data), deleter_(&deleter<BOOL>) {}
MsgData(const std::string* data)
: type_(STRING_STD), data_((void*)data), deleter_(&deleter<std::string>) {}
where deleter_ is a member:
std::function<void(void const*)> deleter_;
and deleter is defined as function template:
template<typename T>
void deleter(void const * data) {
delete static_cast<T const *>(data);
}
Once you have these, your destructor would look like this:
~MsgData() {
if (deleter_) {
deleter_(data_);
}
}
Hope that helps.
I have a class:
class SendData
{
public:
SendData(int SendAMsg(int foo, unsigned char *bar, int length), int number)
{
m_nDefinePos = 0;
m_nOtherStuffDefinedAs =0;
}
void somestuffhere();
void ClearDefinition();
private:
int aLotOfVariableshere;
int m_nDefinePos;
};
This is the class itself. Then some stuff is called:
SendData* m_pData;
m_pData->ClearDefinition();
Which now calls this one:
void SendData::ClearDefinition()
{
printf("Welcome to Clear Definition Script\n");
m_nDefinePos = 0;
// Some more stuff here
}
Here the code breaks somehow. I get the "Welcome to Clear Definition Script" message in my console, but that's all.
It breaks on m_nDefinePos = 0;. (I did put in another printf command after it, never showed in the console.)
I just don't know why it breaks there and i cant find any error.
SendData* m_pData;
m_pData->ClearDefinition();
This declares a pointer, but doesn't create an object or initialise the pointer to point to anything, so calling a member function via the pointer will go wrong. Perhaps you wanted to create an object:
SendData data(arguments);
data.ClearDefinition();
or perhaps you wanted to initialise the pointer to point an object that already exists:
SendData* m_pData = whatever;
I have the following structure, class and function snippet:
structure:
struct myData
{
short index;
char name[32];
}
class:
class myFoo
{
...
public:
short count;
myData** data;
...
}
function:
int Do_Bar(myFoo vFoo)
{
...
myData* data = *vFoo.data;
for (short i=0; i<vFoo.count; ++i)
{
Printf("%3d %s", data.index, data.name);
}
...
}
function call:
...
myFoo foo;
SomeAPI_GetCompleteObjectList(&foo);
Do_Bar(foo);
...
But my code crashes with these code. But if I removed the parameter and create a myFoo class in Do_Bar() function instead, the code works fine:
int Do_Bar(myFoo vFoo)
{
myFoo foo;
SomeAPI_GetCompleteObjectList(&foo);
...
myData* data = *vFoo.data;
for (short i=0; i<vFoo.count; ++i)
{
Printf("%3d %s", data.index, data.name);
}
...
}
Why is it? And how to resolve this?
EDIT1:
I forgot to mention that the initializations of foo is done before the function call. This was initialized using an API.
I modified the code for this.
You have not given memory to pointer data in line myData* data and trying to assign something to it.Alternative method are either
define myData data then use &data as pointer
or allocate memory using dynamic memory allocation.
You have a couple of undefined behaviors in that little piece of code...
You have a double-pointer, but never "point" either of them to anything. This mean they will point to random memory locations.
You print an uninitialized character array, which means it contains random data.
And since you don't do any initialization at all, foo.count will also contain a random value, which may be negative or very large.
And last bot not least, like I said in my comment, that code should not even compile as you use the wrong syntax for the access of the members in the structure.