Compilation error when a shared_ptr<string> is not initialized using initializers list - shared-ptr

In the following code, pName_ has been initialized inside a constructor's body, which during compilation throws error as :
error: no match for call to ‘(std::shared_ptr >) (std::string)’*
pName_(new string(name));
However if i change the way it is initialized, by initializing it using initializers list, then it works fine. Why?
class Person
{
public:
Person(string name) //: pName_(new string(name)){} /*UNCOMMENT THIS*/
{
pName_(new string(name));
}
void printName(){ cout<<endl<<*pName_; }
private:
shared_ptr<string> pName_;
};
int main()
{
vector<Person> persons;
Person p("George");
persons.push_back(p);
return 0;
}

You are trying to use initialiser list syntax in the body of the constructor - essentially you're calling the () operator on pName_ with the parameter of a string, this will not initialise your object and is the reason for the compilation error.
You should favour initialiser list syntax anyway as it means your member won't be default constructed, then thrown away and re constructed by the body of your constructor.
To compile, you either need to use the copy or assignment operators. I would also advocate the use of make_shared over operator new.

Related

Rust Destructors and ownership

I almost asked the same question the other day but in context of c++.
I try to replicate destructors and constructors in my c programming. That means for every object or struct there is an initialization function and a destruct function which frees all of the objects resources like so:
struct MyObject {
struct string a;
struct string b;
struct string c;
};
void ConstructMyObject(struct MyObject *obj) {
ConstructString(&obj->a);
ConstructString(&obj->b);
ConstructString(&obj->c);
}
void DestructMyObject(struct MyObject *obj) {
DestructString(&obj->a);
DestructString(&obj->b);
DestructString(&obj->c);
}
The destruct function is called at the end of every function scope just like in Rust only that i put it manually there instead of the compiler doing the job for me. So now in DestructMyObject function I call the destructors of every struct string type because for the struct string object i would also have a destruct function written just like for the struct MyObject Object. So everything that struct MyObject has allocated will be freed.
Example with my problem:
int main {
struct MyObject Object1;
ConstructMyObject(&Object1);
...
...
...
TransferOwnershipFunction(Object1.b); /*takes a struct string object as argument*/
...
...
...
DestructMyObject(&Object1);
return 0;
}
I transfered ownersnip of a member (struct string b) of Object1 to another function. But struct string b will be freed by the main function because i have the rule that when an object goes out of scope i call its destruct function. But I don't want the main function to free this resource. TransferOwnershipFunction(...) is now responsible to free this member of object1. How does the Rust compiler deal with such situations? In Rust would i have to make a clone of string b?
The Rust compiler is smart enough to see when only a single field of a struct is consumed. Only that specific field has its ownership transferred and the remaining fields are dropped at the end of the scope (or otherwise consumed). This can be seen in the following example.
struct MyObject {
a: String,
b: String,
c: String,
}
fn consume_string(_string: String) {}
fn main() {
let object = MyObject {
a: "".to_string(),
b: "".to_string(),
c: "".to_string(),
};
consume_string(object.b);
// We can still access object.a and object.c
println!("{}", object.a);
println!("{}", object.c);
// but not object.b
// println!("{}", object.b);
}
(playground)
However, if the struct has a non-trivial destructor, i.e., implements the Drop trait, then this can't happen. Trying to move a single field of the struct will result in a compiler error, as seen below.
struct MyObject {
a: String,
b: String,
c: String,
}
// This is new
impl Drop for MyObject {
fn drop(&mut self) {
println!("dropping MyObject");
}
}
fn consume_string(_string: String) {}
fn main() {
let object = MyObject {
a: "".to_string(),
b: "".to_string(),
c: "".to_string(),
};
consume_string(object.b);
}
Attempting to compile this gives the error
error[E0509]: cannot move out of type `MyObject`, which implements the `Drop` trait
--> src/main.rs:22:20
|
22 | consume_string(object.b);
| ^^^^^^^^
| |
| cannot move out of here
| move occurs because `object.b` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0509`.
error: Could not compile `playground`.
(playground) ([E0509])
I think you already understand the reasoning for this, but it's worth repeating. If Drop is implemented for a struct, the destructor might have non-trivial interactions between the fields; they might not just be dropped independently. So that means that the struct has to stay as one coherent piece until it's dropped.
As an example, the Drop implementation for Rc<T> checks if there are any (strong) references to the data left and if there aren't, drops the underlying data. If the fields of Rc<T> (a pointer, a strong reference count and a weak reference count) were dropped separately, there would be no way to check how many strong references were left when dropping the pointer. There'd be no way to keep the underlying data around if there are still strong references.
As you guessed, in the case where Drop is implemented, you'd have to clone the field if you still wanted to consume it.

How to fix errors in function returning pointer pointing to a structure data

I am trying to access data in the structure type function through a pointer. When i do it, i am getting 3 errors
#79 expected a type specifier
#159 declaration is incompatible with previous "memcmp"
Header file:
typedef struct
{
uint8 a[50];
uint8 b;
uint8 c;
} get;
.c file:
main.c()
{
get example[3];
get* example(void)
{
uint_8 l_LoopCounter_u8;
example1_st.a[l_LoopCounter_u8++] = data;
example.b = data;
example.c = data;
return (void*)&example1_st ;
}
}
Here is code which fixes the errors you ask about and a few others.
Without a MCVE it is hard to get it completely working.
You have some design changes coming up, to make the function work on any kind of variable, not only globals.
Making a nested function is not a good way to make a local variable accessable in a funciton. Get the code working on a global, then change to work on call-by reference variables.
The ++ indicate a more complex plan you are following. Do that later.
get example1_st[3]; // changed to the obviously intended name,
// should fix 'declaration is incompatible with previous "memcmp"'
// made this a global, to keep it accessable from function,
// make the code work, then refactor to have the function work on
// variables via call-by reference parmeters
// avoid nested function definition
get* example(void)
{
uint_8 l_LoopCounter_u8=0; // init index variable
example1_st.a[l_LoopCounter_u8] = data; // removed ++, which is unnclear/risky here
example1_st.b[l_LoopCounter_u8] = data;
example1_st.c[l_LoopCounter_u8] = data;
return &example1_st ; // no need to cast to void, type is correct
}
int main(void) //changed to a correct main function head,
// should fix "expected a type specifier"
{
// note that your main function was functionally empty anyway...
}
Note:
No, I did not test this code. It would be hard for lack of a MCVE by OP.
This is meant to help with problems, not deliver working code for unknown purpose.

Accessing enum Members in C

I have a function that is of type of a struct, which contains some integers and a reference to an enum, as such:
typedef struct Test {
Error e;
int temp;
int value;
}Test;
Where the enum is:
typedef enum Error {
IOError,
ExternalError,
ElseError,
}Error;
And say I have a function that wants to return an error (Of an enum of the 3), depending on if something happens.
Where the function is of type Test (I can't change any types or values passed in),
Why can't I return the error like this? How would I go about returning it (I can't change the struct definitions nor the function prototypes).
Test errorFunc() {
return Test->e->IOError; //gives an error
}
Any help would be greatly appreciated!
You don't need to, just do this
Error
errorFunc()
{
return IOError;
}
In c there are no static struct members, nor namespaces so you just use the enum value1 directly.
Also, in c++ you woudn't use the -> indirection operator for that instead you do something like this
class Test
{
public:
enum Error
{
IOError
};
};
And then you can have
Test::Error
errorFunc()
{
return Test::IOError;
}
Which is apparently why you are confused.
1An enum is not a struct so technically it has no members
In C, you would code:
Test errorFunc() {
return IOError;
}
This is C, everything is in the global namespace, there are no "strong" enums and enum "members" are basically "weakly typed integer constants". So, accessing a "data member" of an enum makes no sense. Just use the constant.
Compiler will check if the constant used is of the type you return and complain if it isn't. How much it will complain depends on the compiler, as enums are a little strange weak type concent (Stroustrup once called them "curiously half baked concept").

C multilevel inheritance recursion

I have a project that must be in C (just to avoid the use C++ arguments).
The project depends on virtual tables and pointers to implement polymorphism.
Im stuck however in implementing super constructors from multi-level inheritance.
An example structure is:
Base Object
/\ /\
Constructed Object Simple Object
/\
SpecificConstructed
All objects have a name and a class.
Constructed objects may have a list of sub objects for example.
As simple object may only add a single value.
Base Object is just defined as:
struct _object {
struct _class *class;
char *name;
}
Class is where the virtual table is:
struct _class {
struct _class *super;
char *name;
size_t size;
void* (*init)(void *_this, char *name);
...
}
A constructed object is:
struct _constructed_object {
struct _object base;
void* components; //a list of sub objects for example
}
A sample simple object is:
struct _simple_object {
struct _object base;
unsigned char value; //a simple value for this specific type
}
So every object has a class, and classes can have supers, specially for the SpecificConstructed -> Constructed.
The definitions i have:
struct _class base = {0, "Base", sizeof(struct _object), base_init};
struct _class constructed = {&base, "Constructed", sizeof(struct _constructed_object}, constructed_init};
struct _class specific = {&constructed, "SpecificConstructed", sizeof(struct _constructed_object), specific_init};
struct _class simple = {&base, "SimpleOBject", sizeof(struct _simple_object}, simple_init};
This definition allows me to create objects of specify classes using a function:
new(struct _class *a_class) {
...
struct _object *o = calloc(1, a_class->size);
o->class = a_class;
o = a_class->init(o);
return o;
}
The idea is if i do:
new(SpecificConstructed)
New would create the appropriate space (sizeof(struct _constructed_object)), it would call "specific_init", which in turn would call "constructed_init" (it's super), which finally would call "base_init" (it's super). However the flow is specific_init, constructed_init, specific_init, constructed_init ...
The function i have for calling the supers initializer:
void* super_init(void* _this, char *name){
struct _object *o = (struct _object*)_this;
const struct _class *c = o->class;
const struct _class *s = c->super;
return (s && s->init) ? s->init(_this, name) : _this;
}
The simple (to - super) base method call works since i can just call the supers init.
But for the specific constructed, calling super takes me to the constructed object which is the correct step, but then instead of the constructed sending me up to the base_init, it sends me back to the specific_init call. This happens since I'm passing the same _this object which starts with the class specific i understand that, but not sure how to fix it and if its actually possible to fix?
Ive read the Object Oriented C book, but it deals with one-level inheritance Circle->Point, and the Metaclasses chapter just flew over my head. Ive also looked at the Objective-C runtime to see how that handles it, but it also has metaclasses and that i can't comprehend at the moment.
super_init can't work like that, it needs class on which to call super, otherwise (as you discovered) the immediate superclass constructor ends up calling itself over and over. Since each class knows its parent, it can call superclass's init directly. For example, simple.init will call specific.init, which will in turn call constructed.init, and so on.
If you insist on a function to do that for you, you will have to give it the class so it can (trivially) invoke the constructor of the superclass. super in Python 2 is an example of such a design. Python 3 introduces a simpler-to-use super, but it required support from the compiler to figure out the correct class to pass to the underlying function.
This is awesome stuff, I did a bit of that kind of stuff in C in the early nineties, before moving on to C++.
Unfortunately, despite the fact that your question is quite long, it is still a bit vague because it is not showing us certain things, like what is a "constructed object", (why are you calling it like that,) what is the difference between "constructed object" and "simple object", and what is "the simple->base method call". Also, why the size? Also, I think that some sample code showing the actual problem with the invocation of the constructors is necessary.
The one thing that I can tell you right now about this design is that it strikes me as odd that you are storing a pointer to the constructor in the Virtual Method Table. In all object oriented languages that I know, (C++, Java, C#) constructors are never virtual; they look a lot more like "static" methods, which in C parlance are just plain link-by-name methods. This works fine, because every class has built-in, absolutely certain, unalterable knowledge of who its base class is.
Anyhow, chained constructor invocation is supposed to happen like this:
void basemost_init( struct basemost* this, char* name )
{
this->class = &basemost_class;
this->name = name;
...
}
void intermediate_init( struct intermediate* this, char* name )
{
basemost_init( &this->base, name );
this->class = &intermediate_class;
...
}
void descendant_init( struct descendant* this, char* name )
{
intermediate_init( &this->base, name );
this->class = &descendant_class;
...
}
Edit (after some clarifications)
If you want it to look cool at the allocation end, perhaps try something like this: (I am not sure how well I remember my C syntax, so please excuse any minor inaccuracies.)
struct descendant* new_descendant( char* name )
{
struct descendant* this = malloc( sizeof struct descendant );
descendant_init( this, name );
return this;
}
This way, you don't need a size anymore. Also, note that you can pass as many constructor arguments as you want, without being restricted to a fixed, predetermined number of arguments, (which I consider to be extremely important,) and without having to use variadic constructors.
You may also be able to achieve the same thing with a #define macro for all classes, if you promise to use consistent naming, so that the name of each constructor can always be computed as structname##_init, but I am not sure how to pass arbitrary constructor parameters after the this pointer through a macro in C. Anyhow, I prefer to avoid macros unless they are absolutely necessary, and in this case they are not.

Struct Arrays in a Class

I've ran into an error where I keep getting "is not a type name" for the 'use' function in the cpp file. I'm trying to make an array of structs, to store data for "Items". I'm making a text based RPG game, so I'm trying to create an item class, that has a use function, to use the various items (In the struct array) on the characters. I've tried writing this several different ways and calling it other ways, but I can't get this error to go away. Even placing the struct before the class, in the public, etc.
class Items
{
private:
struct eating
{
int itemNumber;
char name[30];
};
public:
Items();
eating useables[10];
void use(useables);
};
void Items::use(useables) // Error is here, tells me useables is not a type name
{
// To use items on characters
}
You need to pass a type and a name to your function:
void Items::use(eating useables)
{
// To use items on characters
}
In the case you just wanted to use the internal useables object, you don't need to pass it to the function and can just write
void Items::use()
{
useables[1].itemNumber = 1; // For instance
}

Resources