What is the required lifetime of objects returned by import() and exect_file()? - boost-python

Below is a condensed form of this example: http://www.boost.org/doc/libs/1_51_0/libs/python/doc/v2/exec.html#examples
Python function to call from C++, stored in the file script.py:
def greet():
return 'Hello from Python!'
The C++ code to execute the Python function:
#include <iostream>
#include <string>
#include <boost/python.hpp>
using namespace boost::python;
void greet()
{
object main = import("__main__");
object global(main.attr("__dict__"));
object result = exec_file("script.py", global, global);
object greet = global["greet"];
std::string message = extract<std::string>(greet());
std::cout << message << std::endl;
}
My question is: do I need to keep the main, global and result objects alive to be able to call greet?

No, you don't. Everything that needs to be alive is kept alive by references held by the greet object, you don't need to hold objects around yourself.

Related

How to access a variable in mumtiple cpp files contain main section in each file?

I want to access a variable in multiple .cpp files. I looked into several resources. I could not solve it though. I am using cmake to build all the codes in this project. Following is an example that exactly matches with my problem. Basically, I want val to print 42 in both code1.cpp and code2.cpp. When, I build these three files it complains: undefined reference to 'he::val' collect2: error:ld returned 1 exit status for both the .cpp files.
header1.h
#ifndef HEADER1_H
#define HEADER1_H
#include <iostream>
namespace he {
extern int val;
}
#endif // HEADER1_H
code1.cpp
#include "header1.h"
#include <iostream>
using namespace he;
int func()
{
std::cout << val << std::endl;
}
int main()
{
val=20;
func();
return 0;
}
code2.cpp
#include <iostream>
#include "header1.h"
using namespace he;
int main()
{
std::cout << val << std::endl;
}
extern int val;
Is a variable declaration. You need, somewhere (in one of your cpp files), to define the variable:
int val;
Actually, since you have two main() functions, these are two separate programs. Then your variable definition needs to be in both, like this:
namespace he {
int val;
}
But your extern declaration in the header file makes your variable global, which is usually frowned upon. It all depends, of course on what your purpose is.
Also, since two main() functions mean two separate programs, there is no variable sharing.

The rule of The Big Three

Iam confused with the below question I did the program as per my understanding but it crashes what am I doing wrong? If someone can please assist me it would be much appreciated.
my main.cpp looks like this:
#include <iostream>
#include <iomanip>
#include "Number.h"
using namespace std;
int main()
{
Number n1(10);
Number n2 = n1;
n2.printNum();
n2.addOne();
n1 = n2;
n1.printNum();
return 0;
}
Then my header file looks like this:
#include <iostream>
using namespace std;
class Number
{
int *p;
public:
Number(int);
void addOne();
void printNum();
};
And the below parts for the constructor I need to complete there where it shows comments that's the part I should complete:
#include <iostream>
#include "Number.h"
using namespace std;
Number::Number(int a1)
{
*p = a1;//write the code needed to initialise the value of the member variable with a1
}
void Number::printNum()
{
cout << "The number is " << *p << endl;
}
void Number::addOne()
{
*p++;//write the code needed to increment the value of the member variable by one.
}
Then the question asks the below what should I do to the code to use the BIG THREE?
Consider the following program. Complete the class definition (where you are asked to) and check the output. You can see that that program works without error once it is completed. However, experts suggest that in any class that uses pointers and the new operator it is better to follow the rule of The Big Three. Modify the class definition to follow the rule of The Big Three and submit the new program and the output. Demonstrate the use of this pointer.
Thank you
Rohan

Mongocxx array of ObjectID in find

I'm trying to populate a query for a C++ using mongocxx driver.
The query in Javascript would be like:
{unit_id: {$in: [ObjectId('58aee90fefb6f7d46d26de72'),
ObjectId('58aee90fefb6f7d46d26de73']
}
}
I was thinking that the following code could work to generate the array part, but it doesn't compile.
#include <cstdint>
#include <iostream>
#include <vector>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
#include <mongocxx/instance.hpp>
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::finalize;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::open_document;
mongocxx::instance instance {};
mongocxx::client client{mongocxx::uri{}};
mongocxx::database db = client["banff_development"];
mongocxx::collection coll = db["units"];
int main()
{
mongocxx::cursor cursor = coll.find
(document{} << "provider_id" << bsoncxx::oid("58aee90fefb6f7d46d26de4a")
<< finalize);
bsoncxx::builder::stream::document unit_filter_builder;
for (auto a: cursor)
{
unit_filter_builder << a["_id"].get_oid();
}
return 0;
}
Where can I find an working example for queries using ObjectId arrays to filter.
To build an array, you need to use the array builder, not the document builder. The declaration of the builder for the array should be bsoncxx::builder::stream::array unit_filter_builder. It also looks like you're missing a couple of includes for the various stream builder types.
As an aside, it's better to shy away from the stream builder, as it's very easy to run into issues when using it. This and this are good examples of the trickiness of using the stream builder properly. Instead of using the stream builder, you can use the basic builder, which has a much simpler implementation and gives you much saner error messages if you make a mistake.

Passing a class member function to for_each

My question is: how do I pass a class member function into for_each
Code I am trying to get to work: (works when function is defined outside of class)
The part which fails is commented out - the one using for_each with function as the class member function
Any advice on how to get this to work?
#include <iostream>
#include <algorithm>
#include <vector>
void my_function(std::string str)
{
std::cout << "processing settings: " << str << std::endl;
}
class Settings_vector{
public:
std::vector <std::string> settings;
Settings_vector(){ // push back vector of objects
settings.push_back("settings 1");
settings.push_back("settings 2");
settings.push_back("settings 3");
settings.push_back("settings 4");
}
void tester(std::string settings_string){
std::cout << "processing settings: " << settings_string << std::endl;
}
};
int main()
{
//std::vector<std::string> my_vector;
Settings_vector settings_vector;
std:: cout << "doing things the non-class way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), my_function); // testing function
// WORKS
/*
std:: cout << "doing things the modern way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), settings_vector.tester); // testing function
// FAILS
*/
std:: cout << "doing things the oldskool way\n" << std::endl;
for (int i = 0;i<settings_vector.settings.size();++i) {
settings_vector.tester(settings_vector.settings[i]);
}
// WORKS
return 0;
}
The easiest way would be to use a lambda expression. A bit more complex approach is to use std::bind() to bind all known arguments (here the instance of the class to the member function) and leave unknown arguments with placeholders _1, _2, etc.
#include <iostream>
#include <algorithm>
#include <vector>
class Settings_vector
{
Settings_vector()
: settings { "settings 1"
, "settings 2"
, "settings 3"
, "settings 4"
}
{}
void tester(std::string settings_string)
{ std::cout << "processing settings: " << settings_string << std::endl; }
public:
std::vector <std::string> settings;
};
int main()
{
Settings_vector settings_vector;
using namespace std;
using namespace std::placeholders; // for _1
// Possibility Nr. 1: Use a Lambda Function
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, [&settings_vector](auto input){ settings_vector.tester(input); }
)
;
// Possibility Nr. 2: Partially bind existing arguments and use placeholders for others
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, std::bind(&Settings_vector::tester, &settings_vector, _1);
)
;
return 0;
}
Explanations:
I think a lambda is straight forward. In the square brackets, you declare what goes into a closure. Here we pass settings_vector. Preceding it with & means that this instance is passed by reference. In the parenthesis, we declare the parameters to the function. I cheated a little bit, as auto in lambda expressions was introduced in C++14, but you can write it as type std::string as well.
std::bind() binds parameters to a function pointer and returns a callable object. If all parameters are present, the returned callable has no parameters and can be called like: callable(). Here, we want a callable to accept the result of the iteration. Thus, we use a placeholder _1, which states that this argument will be changed at call-time. Now 2 things remain:
Getting a pointer to a member function. This is done by using &TypeName::MemberName, in this case &Settings_vector::tester.
Passing a this pointer to a member function call: &settings_vector. When calling a member function, an object must be passed for which this member function is called. Because we just got a pointer to a member function without any bound object to it, that's why the second param is &settings_vector.
For a more concise sintax, use a static class method. I've slightly edited your code for improved readability within the context of your question (aka removing distractions).
#include <iostream>
#include <vector>
class Settings {
public:
std::vector <std::string> settings;
Settings(std::initializer_list<std::string> l)
: settings(l) {
}
static void tester(std::string const& str) {
std::cout << "processing settings: " << str << std::endl;
}
};
int main() {
Settings sv {"settings 1", "settings 2", "settings 3", "settings 4"};
for_each(sv.settings.begin(), sv.settings.end(), Settings::tester);
return 0;
}

Mongodb c++ crashing when inserting into collection inside an object

I am using the mongocxx driver and I am trying to do a basic insert into a collection.
If I simply follow the guidelines presented here, it works fine.
However, if I put the db and collection instances inside an object, the insert crashes at runtime. So, for a simple example, I have a struct with the database and collection instances, and the try to do an insert via these instances after creating an instance of Thing in main():
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/types.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/instance.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/uri.hpp>
struct Thing {
mongocxx::client client;
mongocxx::database db;
mongocxx::collection coll;
void open_connection(const char* host, const char* db_name, const char* coll_name) {
mongocxx::instance inst{};
mongocxx::uri uri(host);
client = mongocxx::client::client(uri);
db = client[db_name];
coll = db[coll_name];
}
};
int main()
{
Thing thing;
thing.open_connection("mongodb://localhost:27017", "test", "insert_test");
auto builder = bsoncxx::builder::stream::document{};
bsoncxx::document::value doc_value = builder << "i" << 1 << bsoncxx::builder::stream::finalize;
auto res = thing.coll.insert_one(doc_value.view()); //crashes
return 0;
}
I realize this can be solved by initiating the database and collection in main and storing only a pointer to the collection inside Thing.
I am however wondering about the reason for the crash, and whether it is possible to put the db an collection instances inside an object at all.
I think the problem could be that mongocxx::instance inst{}; created on stack in open_connection, so at the end of open_connection the inst is destroyed and some data may become undefined.
From documentation:
Life cycle: A unique instance of the driver MUST be kept around.
Move inst to the main function.