I have a clone_ptr implementation, as was shown in this question and I have a problem where I need to create a clone_ptr from a raw pointer returned from a function.
Here is the code:
DOMDocument* doc = impl->createDocument(
0, // root element namespace URI.
XML::X(docname.c_str()), // root element name
0); // document type object (DTD).
document.get() = *doc; //No way to assign clone_ptr document to raw doc pointer
Where document& impl are declared as follows:
clone_ptr<DOMImplementation, default_clone<DOMImplementation> > impl;
clone_ptr<DOMDocument, default_clone<DOMDocument> > document;
The createDocument function above returns a raw DOMDocument pointer and is assigned to the local variable doc, now I want to get my document clone_ptr and actually pass it the raw pointer gotten from the create document function. It seems however the compiler is not too happy with this as it says the following:
error C2440: '=' : cannot convert from 'xercesc_3_1::DOMDocument' to 'clone_ptr<T,Cloner>::pointer'
with
[
T=xercesc_3_1::DOMDocument,
Cloner=default_clone<xercesc_3_1::DOMDocument>
]
So my question is how can I allow a raw pointer to be explicitly or implicitly converted to a clone_ptr?
EDIT:
Clone specialization:
template<typename T>
struct default_clone
{
static T* clone(T* pPtr)
{
return pPtr ? pPtr->clone() : 0;
}
};
template<>
struct default_clone<DOMDocument>
{
static DOMDocument* clone(DOMDocument* pPtr)
{
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(XML::X("Core"));
return pPtr ? impl->createDocument(0, XML::X(""), 0) : 0;
}
};
template<>
struct default_clone<DOMImplementation>
{
static DOMImplementation* clone(DOMImplementation* pPtr)
{
return pPtr ? DOMImplementationRegistry::getDOMImplementation(XML::X("Core")) : 0;
}
};
Giving your clone_ptr implementation, and the fact that doc is a pointer, wouldn't it be document.reset(doc)?
I don't know the library but would be very surprised if document.get() returned an l-value (thus your assigning something to it seems rather strange). That doesn't mean it won't compile as very few people implement return types as const (ie. returning a constant as the temporary), just that the assign won't have the desired effect.
Related
I have an api call which populates an array of raw pointers to be used by the caller. This function heap allocates each raw pointer but does not allocate the array.
I cannot change this API function regardless of how bad it is.
Calling the api function code looks something like this:
size_t response_count = api.getResponseCount();
std::vector<Response*> responses(response_count);
api.getResponses(responses.data());
for(auto response : responses) {
// Do some processing with response
delete response;
}
I would like to wrap each response in a unique_ptr such that it is still cleaned up at the end of the loop iteration without having to explicitly call delete. Ideally, this would look something like:
for(std::unique_ptr<Response> response : responses) {
// Do some processing with response
// No need to delete response, it will be cleaned up as it goes out of scope
}
This does not compile because the compiler cannot convert a pointer to a unique_ptr:
error: conversion from ‘Response*’ to non-scalar type ‘std::unique_ptr<Response>’ requested
Is there way to cast each element of the container to a smart pointer in this way, or do I need to explicitly delete the raw pointer?
Instead of wrapping each pointer in a unique_ptr, I'd consider using a Boost ptr_vector.
Assuming the data is allocated so you actually can use delete to delete it, the code would look something like this:
size_t response_count = api.getResponseCount();
// Unfortunately, we have to define, then resize. It has a ctor that takes a size,
// but it treats that as an amount to reserve rather than an actual size.
boost::ptr_vector<Response> responses;
responses.resize(response_count);
api.getResponses(responses.c_array());
for(auto response : responses) {
// Do some processing with response
}
...and when responses goes out of scope, it will delete all the objects pointed to by the pointers it contains. If necessary, you can specify an Allocator class that defines how the objects are allocated and deleted.
Reference
https://www.boost.org/doc/libs/1_71_0/libs/ptr_container/doc/ptr_container.html
Though not considered good practice, you can derive from unique_ptr with a non explicit constructor.
template<typename P>
struct MakeUnique : std::unique_ptr<P> {
MakeUnique(P* p) : std::unique_ptr<P>(p) {}
};
This can then be used like this:
for ( MakeUnique<Response> resp : responses ) {
...
}
Probably the closest thing to a one-liner. See working version here.
You can create a wrapper for the vector<response*> that hands out unique pointers
struct wrapper{
struct iterator {
iterator( std::vector<response*>::iterator it ) : it_(it){}
friend bool operator!=( iterator const& lhs, iterator const &rhs ){ return lhs.it_ != rhs.it_; }
void operator++(){ ++it_;}
std::unique_ptr<response> operator*(){ return std::unique_ptr<response>(*it_); }
private:
std::vector<response*>::iterator it_;
};
wrapper( std::vector<response*>& rs ) : rs_{rs} {}
iterator begin() const { return iterator{rs_.begin()}; }
iterator end() const { return iterator{rs_.end()}; }
private:
std::vector<response*>& rs_;
};
You can then iterate over the responses like this:
for( auto resp : wrapper( responses ) ){...
}
See working version here.
If I create a class in c++, it is possible to call a function of an object of this class, even if this class does not exists.
For example:
Class:
class ExampleClass
{
private:
double m_data;
public:
void readSomeData(double param)
{
m_data = param;
}
}
Any function where this class is used:
int main()
{
ExampleClass* myClass;
myClass->readSomeData(2.5);
}
Ofcourse this wouldn't function, because myClass is not defined.
To avoid such situations, I check if ExampleClass objects are a null_ptr
example:
void readSomeData(double param)
{
if(this == null_ptr)
return;
m_data = param;
}
But gcc says:
'this' pointer cannot be null in well-defined C++ code; comparison may
be assumed to always avaluate to false.
Ofcourse that is only a warning, but I think it is not nice to have this warning. Is there a better way to check if the pointer of a class is defined?
Testing it in the class is the wrong way, the warning is correct about that if your code is well defined then this must not be null, so the test should happen at the time when you call the member function:
int main()
{
ExampleClass* myClass = nullptr; // always initialize a raw pointer to ensure
// that it does not point to a random address
// ....
if (myClass != nullptr) {
myClass->readSomeData(2.5);
}
return 0;
}
If a pointer must not be null at a certain part of your code then you should do it according to CppCoreGuideline: I.12: Declare a pointer that must not be null as not_null
Micorosoft provides an Guidelines Support Library that has an implementation for not_null.
Or if possible then don't use pointers at all but std::optional.
So a code setup could look like this:
#include <gsl/gsl>
struct ExampleClass {
void readSomeData(double ){}
};
// now it is clear that myClass must not and can not be null within work_with_class
// it still could hold an invalid pointe, but thats another problem
void work_with_class(gsl::not_null<ExampleClass*> myClass) {
myClass->readSomeData(2.5);
}
int main()
{
ExampleClass* myClass = nullptr; // always initialize a raw pointer to ensure
// that it does not point to a random address
// ....
work_with_class(myClass);
return 0;
}
The best way is not use pointers at all:
int main()
{
ExampleClass myClass;
myClass.readSomeData(2.5);
}
That way there's no need for any check, and in fact, checking this inside the function is moot.
If you need nullability, use std::optional instead.
Either don't use pointers as Bartek Banachewicz has pointed out, or properly initialize and check the pointer:
int main()
{
ExampleClass* myClass= 0;
if (myClass)
myClass->readSomeData(2.5);
return 0;
}
Of course you still have to add the instantiation of the object at some point, otherwise the code is nonsense.
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'm trying to call a method to add to an object to a vector within another object. I'm getting the error;
'': Illegal use of this type as an expression
Within my program I declare an object to store my node in the main;
accountStream *accountStore = new accountStream;
Then call the function;
new_account(&accountStore);
The new_account function is as;
void new_account(accountStream &accountStorage)
{
newAccount *account = new newAccount;
(&accountStorage)->pushToStore(account);
}
The account stream class has a vector that receives it, but there is where my error is;
class accountStream
{
public:
accountStream();
~accountStream();
template <class account>
void pushToStore(account);
private:
std::vector <newAccount*> accountStore;
};
template<class account>
inline void accountStream::pushToStore(account)
{
accountStore.push_back(account);
}
The error is on the second last line;
accountStore.push_back(account);
I've got a feeling it's something to do with the way I'm passing the object into the method, but after messing around for a while I haven't been able to pinpoint where exactly I've gone wrong.
2 problems:
new_account(&accountStore); is wrong, use new_account(*accountStore); to match the argument type.
accountStore.push_back(account); is wrong. account is type not object. Add some argument to the function.
Several issues:
You must specify the variable name here (and not only the type):
template<class account>
inline void accountStream::pushToStore(account c)
{
accountStore.push_back(c);
}
You must receive a pointer (not a reference to a pointer) here
void new_account(accountStream *accountStorage)
{
newAccount *account = new newAccount;
accountStorage->pushToStore(account);
}
You must call the function with a pointer as a parameter:
new_account(accountStore);
Alternatively, you can declare the variable (not a pointer to):
accountStream accountStore;
call the function:
new_account(accountStore);
and receive a reference:
void new_account(accountStream &accountStorage)
{
newAccount *account = new newAccount;
accountStorage.pushToStore(account);
}
As answered here already, you need to use *accountStore and not &accountStore because the function takes a reference and not a pointer to a pointer (which is what you get from using & operator on a pointer).
the second problem is here:
template<class account>
inline void accountStream::pushToStore(account)
{
accountStore.push_back(account);
}
you are declaring the function templated on the 'account' therefore account is a type, and what you are trying to do in the next line is push_back a type and not an object.
the correct code would be:
template<class account>
inline void accountStream::pushToStore(account acct)
{
accountStore.push_back(acct);
}
because account is the type while acct is an instance of the type account.