Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I am writing a wrapper around a C-API.
(i) Let capi_array_data capi_get_array(void) be a function contained within this library returning a struct containing metadata about a heap-allocated array managed by said API. It would look something like struct capi_get_array { size_t length; int* arr }; (using int for simplicity)
(ii) Such an array can be created by the user manually with malloc, new, std::vector, etc. It must then be registered with void capi_register_array(int*).
I want to make a wrapper class, call it MyArrayWrapper, managing such an array with the anatomy of an STL container, supporting operator[], begin, back, etc. In (i) this wrapper would not own the data, but in (ii) it would. My question now is, whether I should
(a) have one single class that can be constructed using either a std::initializer_list (or variadic template for that matter) or an int* returned by the API;
(b) have separate classes named something like MyArrayWrapperRef and MyArrayWrapper, the first handling (i) and the second handling (ii);
(c) optimally have the syntax MyArrayWrapper& for (i) and MyArrayWrapper for (ii); can this be done?
With (a) there could come up confusion, as one class does two things, which breaks the single-responsibility principle. Answers to questions like "does the copy constructor conduct a deep of shallow copy?" will not be obvious and would require further documentation.
(b) seems like a good choice, but now there are multiple cases: MyArrayWrapper, MyArrayWrapper&, MyArrayWrapperRef, MyArrayWrapperRef&. How would they differ? What about const references? This might even require another class MyArrayWrapperConstRef and again leads to confusion.
(c) is optimal and seems natural with other classes, but I don't know of a way to make it work. I could make a wrapper around capi_get_array returning a MyArrayWrapperRef, but I would have to save the source of the reference somewhere, right?
With (a) there could come up confusion, as one class does two things,
which breaks the single-responsibility principle.
You can also see it the other way around: The single responsibility of the wrapper is to hide the real ownership and who cleans up what.
Lets say you have this:
struct arr_data {
int* a;
unsigned size;
};
arr_data get_arr(){
arr_data ret;
ret.size = 5;
ret.a = new int[ret.size];
return ret;
}
void reg_arr(arr_data x){
static arr_data store = x;
}
Then a simple wrapper could look like this:
struct wrapper {
std::shared_ptr<arr_data> data;
// implement container-like interface
};
wrapper make_non_owning_wrapper() {
auto res = new arr_data();
*res = get_arr();
return { std::shared_ptr<arr_data>(res,[](arr_data* x){
std::cout << "delete x only\n";
delete x;
}) };
}
wrapper make_owning_wrapper() {
auto res = new arr_data();
res->size = 5;
res->a = new int[res->size];
return { std::shared_ptr<arr_data>(res,[](arr_data* x){
std::cout << "delete both\n";
delete[] x->a;
delete x;
})};
}
int main(){
auto v = make_owning_wrapper();
auto w = make_non_owning_wrapper();
auto z = v;
}
Using a shared pointer you can choose a) what to do on clean up and b) what happens when copying a wrapper without causing great confusion ;).
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 11 months ago.
Improve this question
So, I know a vector object can be declared and initialized like this:
// Nothing new here. I know <int> is a template
// and how to implement it:
vector <int> vect{ 10, 20, 30 };
I assume that the vector object has inside an array of values, and the functions of that class (like push_back() for example) manage it. I would like and have been trying to implement something like that in a class of my own, without success. Would be interesting being able to understand how it's done! Did many "experiments" but none worked.
// Random named class:
class A_Class
{
private:
// A pointer for the type I want:
int *A_pointer_To_int;
public:
// Trying to accept the input values between
// brackets and putting them inside a temp array:
A_Class(int Input_Array[]) {}
};
int main()
{
// trying to create the object like in the vector class.
// Returns error "No instance of constructor matches the argument list":
A_Class My_Object{1,2,3}
return 0;
}
In a function parameter, int Input_Array[] is just syntax sugar for a decayed pointer int* Input_Array, which does not provide any information about any array that may be passed in to it.
For what you are attempting, you need to accept a std::initializer_list instead, eg:
#include <initializer_list>
#include <algorithm>
// Random named class:
class A_Class
{
private:
// A pointer for the type I want:
int *A_pointer_To_int;
// the number of values in the array:
size_t size;
public:
A_Class(std::initializer_list<int> Input_Values) {
size = Input_Values.size();
A_pointer_To_int = new int[size];
std::copy(Input_Values.begin(), Input_Values.end(), A_pointer_To_int);
}
~A_Class() {
delete[] A_pointer_To_int;
}
};
int main()
{
A_Class My_Object{1,2,3}; // works now
return 0;
}
Online Demo
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have a method in class like this:
int Class1::addObject(Struct1 object)
{
object.objectID = objCounter;
objCounter++;
vector1.push_back(object); // this line throws exception
// unrelated line
return object.objectID;
}
Vector is defined and initialized as following:
std::vector<Struct1> vector1 = {};
The biggest problem is that this exception occurs sometimes and I am afraid that there is memory leakage.
I am using C++14 and I don't think there is problem with that (because I read somewhere that before C++11 vector was not allowed). Also the Struct1 object is initialized before calling this method, so it isn't about that neither.
Could it be because Visual Studio doesn't have Administrator privileges or it may be due to vector changing location in memory when adding more elements and process couldn't allocate more memory (I think this can be it)? The third possible suspect is multithreading: since I am accessing Class1 with 4 threads at the time, but every thread has it's own group of objects that it adds/removes, and that group is never the same for 2 or more threads?
Update 1:
Definition of Struct1 (copy and default constructors are added when someone suggested in answers)
struct Struct1
{
int objectID;
Struct1ObjectType objectType;
GLfloat array1[2];
GLfloat array2[3];
GLfloat objectSize;
Struct1() {}
Struct1(const Struct1& cs1)
{
objectID = cs1.objectID;
objectType = cs1.objectType;
for (int i = 0; i < 2; i++)
array1[i] = cs1.array1[i];
for (int i = 0; i < 3; i++)
array2[i] = cs1.array2[i];
objectSize = cs1.objectSize;
}
};
Re:
The third possible suspect is multithreading: since I am accessing Class1 with 4 threads at the time, but every thread has it's own group of objects that it adds/removes, and that group is never the same for 2 or more threads?
Regardless of objects being different, you can't access the same vector from multiple threads without synchronization.
One way of doing this is with mutex:
std::mutex m_lock;
then when you need to access that vector:
{
const std::lock_guard<std::mutex> l(m_lock);
vector1.push_back(object); // this line throws exception
}
The C++ standard library uses "copy semantics" for elements in its collections. The code line vector1.push_back(object); cause the copy-construction of a Struct1 object (the object that is stored inside the std::vector<>, which is a copy of the object that is in the parameter).
You haven't shown the definition of class Struct1 so I don't know how it's being copy-constructed, but I would check there to see if you have a programming bug in that code.
I am going over a mock exam in revision for my test, and one question on the paper confuses me.
Q.)An application is required to pass a structure to a function, which will modify the contents of the structure such that on return from the function call the caller can use the new structure values. Would you pass the structure to the function by value, address or reference?
State clearly why you chose a particular method. Justify your choice by comparing the three methods.
Now I have difficulty understanding this, because I assume the best answer to the question would always be by Ref as that takes the reference pointer of the value and edits its contents rather than just getting a copy. This would be different if using a class based program.
The only other method I would understand would be having a separate value and getting and setting the values, but this would mean extra lines of code, I am a little unsure on what this means, can anyone help enlighten me ? I do not know any other methods to achieve this.
This is not "advanced programming"; it is the absolute basics of C++.
Whether return-by-value or "out" parameters (implementing using references or pointers) are "best" for any given use case depends on a number of factors, style and opinion being but two of them.
// Return by value
// T a; a = foo(a);
T foo(const T& in) // or: T foo(T in)
{ // {
T out = in; //
out.x = y; // in.x = y;
return out; // return in;
} // }
// Out parameter (reference)
// T a; foo(a);
void bar(T& in)
{
in.x = y;
}
// Out parameter (pointer)
// T a; foo(&a);
void baz(T* in)
{
in->x = y;
}
The question is asking you what the pros and cons are of these three approaches.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I saw this particular code:
void GetMe(User& user) {
std::cout << user.getName() << std::endl;
}
main(...) {
User* user = new User("Joe");
GetMe(*user);
getchar();
return EXIT_SUCCESS;
}
I cannot find an example for this in particular on any question here on Stack overflow only some with (&*) instead of (&) and I don't understand what is the point behind it, is it for safety in case the pointer is deleted somewhere else ? (It's a multi threaded app)
When you pass a user defined type to a function, you can use one of the following approaches:
Pass by value:
void GetMe(User user) { ... }
Pass by pointer:
void GetMe(User* userPtr) { ... }
void GetMe(User const* userPtr) { ... }
Pass by reference:
void GetMe(User& user) { ... }
void GetMe(User const& userPtr) { ... }
As a rule of thumb, passing by reference is preferable to passing by value or passing by pointer.
When you pass by reference instead of by value, the cost of copying an object is avoided.
When you pass by pointer, you cannot assume that a nullptr won't be passed. So, you have add checks in GetMe to account for that case. You don't worry about that when you pass by reference.
I believe you are asking why the code wasn't written as:
void GetMe(User* user) {
std::cout << user->getName() << std::endl;
}
main(...) {
User* user = new User("Joe");
GetMe(user);
getchar();
return EXIT_SUCCESS;
}
But a lot of experienced programmers would instead ask why it wasn't.
void GetMe(User const& user) {
std::cout << user.getName() << std::endl;
}
main(...) {
User* user = new User("Joe");
GetMe(*user);
getchar();
return EXIT_SUCCESS;
}
In both examples, I am ignoring the more serious issue of the memory leaking non-smart pointer and just looking at how user is passed to GetMe.
The original vs. the way I think you are asking about is largely a style question. I don't see a multi-threading or other functional difference (as you asked about) nor a strong argument for either style.
But I do see strong arguments for tagging it const when passed either by pointer or reference. If getName() is not const (causing it to be harder to make user const) then that likely should also be fixed.
As I see it, there are two parts to your question:
Why the interface, void GetMe(User& user) { } instead of void GetMe(User* user) {}? There can be several reasons:
void GetMe(User& user) { } implies a malleable non-null input and output user. If you want non-malleable or input-only, use void GetMe(User const& user) { }. If you want nullable, use pointers, etc...
How you pass parameters in C++ has very specific semantics, so you must be careful how you do it. They all have different meanings: passing by reference, by pointer, by const reference, by const pointer, etc...
Why User* user = new User("Joe"); instead of User user("Joe");? There may be reasons why you want to allocate memory dynamically on the heap rather than locally on the stack. For example, if you want the lifetime of the object to be longer than the closing brace. Another reason used to be that if User is a really large object, then you want it on the heap (with modern CPUs, this may be less of an issue).
Note that multi-threading is an entirely different can of worms. You have to worry about memory visibility, synchronisation, mutexes, race conditions, etc... ...most of those issues are orthogonal to the two points above. I recommend that you get a good handle basic C++ semantics before you head down that road, if you don't want to end up wasting a ton of time debugging threading problems.
By default, parameters pass by value to function, i.e.without & , you have a copy of your parameter in function - just copy of its value ,not its reference- i.e. you don't have your real parameter in function and if you have to do some operations with address(refrence) of parameters, everything going to wrong.
Consider this example: a function that could not be to allocate memory to its parameter (char) :
void al(char * c) //wrong way: pass by value
{
c =new char[10];
}
main()
{
char * x;
al(x);//don't allocated because pass by value/.
*x='a';//memory error//
}
but this function declaration can do this because pass by reference:
void al(char * & c)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am using a c library to do integration, where the integrand is declared as fun(...,void *fdata,...)
which uses *fdata pointer to pass external variables, however, before doing numerical integration, I need to
interpolate the raw data using other c++ libraries, giving back some interpolating class objects,
basically I want to pass these objects to a integrand which is user-defined ...
You could use an structure and pass a pointer to it but it seems to me that you don't have a fixed number of objects to pass and therefore that an object aggregating others dynamically would suit better your needs so you can use a std::vector and pass its address as func fdata parameter.
An example:
#include <vector>
#include <iostream>
using namespace std;
class C //Mock class for your objs
{
public:
C(int x)
{
this->x = x;
}
void show()
{
cout << x << endl;
}
private:
int x;
};
void func(void *fdata) //Your function which will recieve a pointer to your collection (vector)
{
vector <C *> * v = (vector<C *> *)fdata; //Pointer cast
C * po1 = v->at(0);
C * po2 = v->at(1);
po1->show();
po2->show();
}
int main()
{
vector<C *> topass;
topass.push_back(new C(1)); //Create objects and add them to your collection (std::vector)
topass.push_back(new C(2));
func((void *)(&topass)); //Call to func
for(vector<C *>::iterator it = topass.begin(); it != topass.end(); it++)
delete(*it);
}