Objects with primitive data pointers and emscripten - c++

Rephrasing the question:
How should I bind a function that returns an object with an array as member variable from a C/C++ API to javascript when I don't know the length of the array a priori?
I have a struct with a primitive data type pointer
struct Person
{
const char* name;
int age;
Person()
{}
};
and I have a function that should return this an object of this struct
Person getPerson()
{
Person p = Person();
p.name = "Philipp";
p.age = 77;
return p;
}
and following embindings:
EMSCRIPTEN_BINDINGS() {
value_object<Person>("Person")
.field("age", &Person::age)
.field("name", &Person::name)
;
function("getPerson", &getPerson);
}
This doesn't work and the compiler also tells me static_assert failed "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>"
I tried to understand API documentation but I couldn't make it work. E.g. I tried to add allow_raw_pointer() (and variants of this) to the .field of name.

class_::property can specify getter and setter function.
std::string getPersonName(const Person& p) {
return p.name;
}
EMSCRIPTEN_BINDINGS() {
class_<Person>("Person")
.property("age", &Person::age)
.property("name", &getPersonName)
;
function("getPerson", &getPerson);
}
/*
var p = Module.getPerson();
console.log(p);
console.log(p.age);
console.log(p.name);
*/

Related

How do I access the contents of a std::shared_ptr?

Here is my code.
std::shared_ptr<WSUStudent> WSUStudent::registerStudent(
std::string lastName,
std::string firstName
)
{
auto result = std::shared_ptr<WSUStudent>(new WSUStudent(lastName, firstName));
s_allStudents.insert(&result);
return result;
}
I have successfully managed to change the function so it returns a shared_ptr instead of a normal pointer. I have successfully encapsulated the 'new' statement with a shared pointer, as per the assignment (I think), but the line of code below 'auto' didn't work without the &, and it doesn't work WITH the &. I receive an error stating that there is no matching function call, with or without the &. That line of code is attempting to insert the new student (or a pointer to the new student?) into the list of all students. However the 'insert' method is not locally overridden, so I'm not quite sure what to do here. Error printed below.
/mnt/hgfs/Data Structures and Algorithms/HW04/WSUStudent.cpp:146:32: error: no matching function for call to ‘std::set<WSUStudent*>::insert(std::shared_ptr<WSUStudent>*)’
s_allStudents.insert(&result);
The point of this assignment is to fix memory leaks ('new' statements that don't get deleted with their pointers) by turning normal pointers into weak pointers and shared pointers. The original code is as follows.
WSUStudent *WSUStudent::registerStudent(
std::string lastName,
std::string firstName
)
{
auto result = new WSUStudent(lastName, firstName);
s_allStudents.insert(result);
return result;
}
Am I going about this wrong? I can't get the s_allStudents line to run.
Given the type of s_allStudents, you can use:
s_allStudents.insert(result.get());
However, a better option will be to change type of s_allStudents.
static std::set<std::shared_ptr<WSUStudent>> s_allStudents;
and use:
s_allStudents.insert(result);
Update
The default operator<() of shared_ptr is such that the objects in s_allStudents will be sorted by pointer value. If you would like to sort the objects using a different criterion, you'll need to define a custom functor/function as a parameter of the template.
struct MyCompare
{
bool operator<(shared_ptr<WSUStudent> const& lhs,
shared_ptr<WSUStudent> const& rhs) const
{
// Implement the logic ...
}
};
and use it as:
static std::set<std::shared_ptr<WSUStudent>, MyCompare> s_allStudents;
If you are going to return a std::shared_ptr<WSUStudent> then you are returning ownership rights to the object you created - meaning someone else will be trying to delete it at some point.
Unless you also keep ownership that means your pointer could get deleted before you are finished with it. So you need to also store std::shared_ptr in your static set:
I am guessing at how you are using this class but what I mean goes something like this:
class WSUStudent
{
// you really need to store shared pointers in here
static std::set<std::shared_ptr<WSUStudent>> s_allStudents;
std::string lastName;
std::string firstName;
// only the static factory function can make students
WSUStudent(
const std::string& lastName, // passing by const& is more usual (idiomatic)
const std::string& firstName)
: lastName(lastName)
, firstName(firstName)
{
}
public:
static std::shared_ptr<WSUStudent> registerStudent(
const std::string& lastName,
const std::string& firstName);
};
std::shared_ptr<WSUStudent> WSUStudent::registerStudent(
const std::string& lastName,
const std::string& firstName
)
{
auto result = std::shared_ptr<WSUStudent>(new WSUStudent(lastName, firstName));
// put the shared student in your set
s_allStudents.insert(result);
return result;
}
// define your set
std::set<std::shared_ptr<WSUStudent>> WSUStudent::s_allStudents;
int main ()
{
// make students
auto s = WSUStudent::registerStudent("bill", "bob");
// all deletions should be in order
}

How to convert array pointer into an array argument from template function?

I guess the title is quite confusing, I'll explain my case with some code.
template<uint16_t Len>
void add(const int8_t (&i_array)[Len])
{
// Do something
}
class Test
{
public:
int8_t* GetName()
{
return name;
}
private:
int8_t name[10] = "myname";
}
int main()
{
Test mytest;
add(mytest.GetName()); // Compilation error
}
This code does not compile. The following error is generated :
"Error#304 : no instance of function template add matches the argument list"
It seems that the compilator is not able to determine that GetName() return an array of size 10. Is that right ?
How could I call "add" with a pointer on an array ?
Thanks,
Nicolas
Test::GetName returns a pointer, not an array. You cannot bind its result to a function that expects an array reference. However, you could change the signature of GetName to make it return the array (by reference, of course):
int8_t (&GetName())[10] { return name; }
Alternatively you could use a cast, but that would defeat the purpose of the type system.

illegal call of non-static member function

I'm having trouble with this function below:
char* GetPlayerNameEx(int playerid)
{
char Name[MAX_PLAYER_NAME], i = 0;
GetPlayerName(playerid, Name, sizeof(Name));
std::string pName (Name);
while(i == 0 || i != pName.npos)
{
if(i != 0) i++;
int Underscore = pName.find("_", i);
Name[Underscore] = ' ';
}
return Name;
}
declaration:
char* GetPlayerNameEx(int playerid);
usage:
sprintf(string, "%s", CPlayer::GetPlayerNameEx(playerid));
Now my problem here is
Removed personal information.
If this has anything to do whith it which I doubt it does, this function is contained within a "Class" header (Declartion).
Also I have no idea why but I can't get the "Code" box to fit over correctly.
Illegal call of non-static member function means that you are trying to call the function without using an object of the class that contains the function.
The solution should be to make the function a static function.
This is normally what causes the error C2352:
class MyClass {
public:
void MyFunc() {}
static void MyFunc2() {}
};
int main() {
MyClass::MyFunc(); // C2352
MyClass::MyFunc2(); // OK
}
If making it static is not an option for you, then you have to create an instance of the class CPlayer.
Like this:
CPlayer myPlayer;
myPlayer.GetPlayerNameEx(playerid);
You cannot create these functions as static (without a lot of tweaking) because you are attempting to modify the data of a specific instance. To fix your problem:
class CPlayer
{
public:
// public members
// since you are operating on class member data, you cannot declare these as static
// if you wanted to declare them as static, you would need some way of getting an actual instance of CPlayer
char* GetPlayerNameEx(int playerId);
char* GetPlayerName(int playerId, char* name, int size);
private:
// note: using a std::string would be better
char m_Name[MAX_PLAYER_NAME];
};
// note: returning a string would be better here
char* CPlayer::GetPlayerNameEx(int playerId)
{
char* Name = new char[MAX_PLAYER_NAME];
memset(Name, MAX_PLAYER_NAME, 0);
GetPlayerName(playerId, m_Name, sizeof(m_Name));
std::string sName(m_Name);
std::replace(sName.begin(), sName.end(), '_', ' ');
::strncpy(sName.c_str(), Name, MAX_PLAYER_NAME);
return Name;
}
// in your usage
CPlayer player;
// ...
sprintf(string, "%s", player.GetPlayerNameEx(playerid));
CPlayer::GetPlayerNameEx(playerid)
You can't use the scope (::) operator on a class type to call a function unless it is a static function. To call a function on an object, you actually have to create the memory for that object first (via making a CPlayer variable somewhere) and then calling the function on that object.
Static functions are global and specifically do not mess with member variables of the class (unless they are also static) which makes them valid to call without the scope of an actual object instance.

Copy string value into a class field?

I'm new to and learning C++. I know a fair amount of Java and some C.
What I want to do is to create an immutable name class that takes in a string value, copies that string to a class field and then eventually hashes it to an ID that can be parsed much more efficiently than a string.
I'm hitting a wall due to a general lack of knowledge of C++ strings. Here's what I have so far...
#pragma once
#include <string>
class Name
{
public:
Name(std::string s);
~Name(void);
int getId();
std::string getName();
private:
int id;
std::string name;
};
and...
#include "Name.h"
Name::Name(std::string s)
{
}
So what I want to do is store the value of s, passed in by the constructor in the "name" private field. As far as I know a new string object must be created and then the value of s must be copied into it.
I also think that the argument s can and should be a string pointer instead of a string object (to prevent an unnecessary copy from occurring). If I'm right then the constructor should look like the following, right?
Name::Name(std::string &s) { ... }
In this case, nothing would need to be done special when passing in a name? IE.
Name n = new Name("Cody");
is perfectly valid? Actually I'm not sure since "Cody" to my knowledge is a constant string or something like that.
So if I'm all on the right track, then what is the proper way to actually copy the value? I'm thinking this is appropriate but I'm not sure.
#include "Name.h"
Name::Name(std::string s)
{
name = new string(s);
}
Thanks for the help in advance, I know it's a basic question but I'm slowly making baby steps into the C++ world. :) - Cody
You are close, your code can be like this after a little massage:
class Name
{
public:
Name(const std::string& s); // add const and reference
~Name(void);
int getId() cosnt; // add const
std::string getName() const; // add const
private:
int id;
std::string name;
};
Name.cpp
Name::Name(const std::string& s):name(s)
{
}
Here :name(s) is called member initializer list.
Name n = new Name("Cody"); is perfectly valid? Actually I'm not sure
since "Cody" to my knowledge is a constant string or something like
that.
No, n is not pointer, it's not like java you need to new for every object. In C++, you do
Name n("Cody");
This will call Name(const std::string& s) to initialize object n and initialize name string with "Cody".
Note: variable n has automatic storage duration, it will be destroyed if it goes out of scope.
To let n on dynamic storage duration, you need to use new/delete pair:
Name *pn = new Name("Cody");
delete pn;
or use smart pointers, you no need to call delete n_ptr; as n_ptr will be destroyed when it goes out of scope as well:
#include <memory>
std::shared_ptr<Name> n_ptr(new Name("Cody"));
EDIT:
To use Name class in other classes, it's the same way when you use string in Name class, you don't have to use pointers.
class TestName
{
public:
TestName(const Name& n):name_(n){ }
private:
Name name_;
};
TestName tn("Cody");
You should use a constant reference to std::string here.
As you said, it would prevent unnecessary copies.. But then why not just a pointer or a constant pointer?
A constant reference would allow you to pass to your function some arguments that would implicitly call the right std::string constructor.
So, in a nutshell, you could do that:
Name::Name(const std::string& s)
{
this->name = s;
}
// Or even better..
Name::Name(const std::string& s):
name(s)
{
}
int main(void)
{
Name nick("hello");
return 0;
}
You can find out about every std::string's constructors on its cplusplus.com's sheet.

Why do we use 'this->' and not 'this.' to access members?

I was looking at a library a person has made for FaceBook in C++. The header file is this:
#ifndef __FACEBOOK_H__
#define __FACEBOOK_H__
/**
* Facebook Class
* Joel Seligstein
* Last mod: Aug 22, 2006
*
* This is the beginnings of a facebook class set and REST client. Its not documented
* yet nor nearly complete. But this is a release to demonstrate its usefulness.
* Please email joel#seligstein.com with suggestions or additions.
*
* TODO: Create classes/parsers for each request type
* TODO: Linux URL launcher
*/
//uncomment to have verbose output turned on
//#define fb_debug 1
//define which platform you're compiling for
#define fb_windows 1
//#define fb_linux 1
#include <string>
#include <sstream>
#include <list>
using namespace std;
#ifdef fb_windows
#include <windows.h>
#endif
#include "curl/curl.h"
#include "xmlParser/xmlParser.h"
#include "md5.h"
class facebook
{
public:
//app/session vars
string api_key;
string secret;
string token;
string server;
string session_key;
string session_secret;
string uid;
bool has_session;
facebook( string my_key, string my_secret, string my_server );
bool authenticate( );
bool request( string method, list<string> params, string *res );
bool load_token( );
void launch_login( string url );
bool get_session( );
void clean_up( );
private:
//curl info
CURL *curl;
CURLcode res;
int call_id;
//internal functions
string get_signature( list<string> params );
static string md5( string str );
static string get_param_string( list<string> params, bool separate );
static size_t write_callback( void *ptr, size_t size, size_t nmemb, void *userp );
};
#endif //__FACEBOOK_H__
Then inside the cpp file, my question is regarding this, the below is the constructor:
facebook::facebook( string my_key, string my_secret, string my_server )
{
this->api_key = my_key;
this->secret = my_secret;
this->server = my_server;
this->has_session = false;
this->call_id = 0;
}
Why have they used the -> operator and not .?
I have a limited understanding that -> accesses properties and methods of the type directly in memory but I am confused, I would, through ignorance, expect to see:
facebook::facebook( string my_key, string my_secret, string my_server )
{
this.api_key = my_key;
this.secret = my_secret;
this.server = my_server;
this.has_session = false;
this.call_id = 0;
}
All I want to know is the theory behind why -> is used over the dot notation.
UPDATE:
For anyone else in the same boat as me and learning C++. I have expanded on an example posted by a member in this question. I have also wrapped in initialization list for a member field.
#include "stdafx.h"
#include <iostream>
using namespace std;
class A {
private:
int x;
public:
A() : x(0){}
int getX() const {return x;}
void setX(int xx) {x += xx;}
};
int main()
{
A a;
a.setX(13);
A *pa = &a;
pa->setX(2);
A b = a;
b.setX(5);
cout << "a" << a.getX() << endl;
cout << "a*" << pa->getX() << endl;
cout << "b" << b.getX() << endl;
return 0;
}
this is a pointer to the current object i.e., inside methods (or constructor) of class A, this is of type A *.
(Note that, if the method is tagged as const, this is of type A const *.)
Hence the use of -> (designed only for pointers) and not . (designed only for class objects A or references to class objects A&).
In C++, this is a pointer to the self object. It's a relic leftover from early versions of C++, before it had references. If this were added to the language now, it probably would be a reference, for which you'd use the . notation.
Because inside a class or struct member, "this" is a special pointer that points to the current instance.
Any time you're accessing members of a class or struct through a pointer, the -> operator is used.
If you're accessing them through anything that isn't a pointer (usually a reference), the dot operator is used instead.
It's worth noting that the this-> syntax isn't necessary except in some forms of template instanciation. A lot of people choose to use it for stylistic reasons, though. There are a couple questions related to rationale behind this on S.O. already.
You may consider the following example.
class A {
int x;
public:
int getX() const {return x;}
void setx(int xx) {x = xx;}
};
int main()
{
A a;
a.setX(13);
cout << a.getX() << endl;
A *pa = &a;
cout << pa->getX() << endl;
return 0;
}
Notice that, dot operator (.) is used when calling a member function of A directly with the object a. The arrow operator (->) is used when calling a member function of A indirectly through a pointer of type A (A *pa = &a).
In C++, this is a pointer to the invoking object. Thus we could also define A::getX() function as follows:
int getX() const {return this->x;}
Or:
int getX() const {return (*this).x;}
this is a pointer of object A, thus *this dereferences it. So we could use both of the functions above.
As said, this is a pointer and not a reference. Thus you need the -> operator that is roughly (while not exactly the same as): (*this).
They differ in that you can overload -> operator or * operator in a class and can have different semantics. As a matter of fact, if a class overrides operator-> and the returned value is not a raw pointer, the compiler will keep on applying operator-> to the returned object until it reaches a native pointer. Operator . cannot be overloaded.
In the constructor you pointed, the use of this is completely optional as there is no name collision the code could just have named the attributes without further qualification.
facebook::facebook( string my_key, string my_secret, string my_server )
{
api_key = my_key;
secret = my_secret;
server = my_server;
has_session = false;
call_id = 0;
}
And a better solution would be using an initialization list. If you are interested in learning C++ google for it.
because "this" is a special pointer that refers to the current object and we use "->" to access the members of the object through pointers and "." is used for calling the member of a object directly.