Search code examples
pythonc++python-2.7boost-python

Boost Python 2: Constructors using `std::string &`


I have a legacy code in C++ (which would be a huge pain to edit) and I need to use it in Python 2 for speed reasons.

I have two classes. One is responsible for loading huge amount of data from memory, in a form of std::string and converting it to internal representation MiddleClass. Second one is converting it from internal representation MiddleClass back to std::string.

 class Load {
     Load(const std::string & data) { ... };
     MiddleClass load() { ... };
 };

 class Save {
     Save(std::string & data) { .... };
     void save(const MiddleClass & middleclass) { ... };
 };

My goal is, to use this setup in Python 2 like this:

import datahandler # my lib
import requests

request = request.get("url-to-data")
loader = datahandler.Load(request.content) # my C++ class Load
internal_representation = loader.load()

.
.
.

result_variable = str() # or None or something not important
saver = datahandler.Save(result_variable) # my C++ class Save
saver.save(internal_representation)

How can I achieve this?


I've run into trouble, right from the start.

Simple variant:

BOOST_PYTHON_MODULE(datahandler)
{
     class_<MiddleClass>("MiddleClass");\
     // some .defs - not important

     class <Load>("Load", init<const std::string &>())
         .def("load". &Load::load);

     class <Save>("Save", init<std::string &>())
         .def("save". &Save::save);        
}

Will compile, no worries, but data which are loaded are somehow mangled, which leads me to thinking, that I am doing it terribly wrongly.

Also I found this bit offtopic SO question, which told me, that I can't have std::string &, because Python strings are immutable.

So conclusion: I have no idea what to do now :( Can anyone here help me? Thanks.


Solution

  • So, I have found a solution. Prove me wrong, but I think, that what am I trying to achieve is impossible.

    Python has immutable strings, so passing a "reference" of string to function and expecting ability to change it from inside a function is simply not valid.

    Take this code as an example:

    variable = "Hello"
    
    def changer(var):
        var = "Bye"
    
    changer(variable)
    
    print(variable)
    

    Prints "Hello". In Python, you can't make it work differently. (although to be exact, it is still being passed as a reference, but when you modify Python string, you just create a new one and a new reference).

    So, how to get arround this?

    Simple! Create a C++ wrapper, that will handle passing reference on std::string and return copy of resulting string. Not very effective, but you probably can't make it better.

    Sample code of SaveWrapper class:

    class SaveWrapper {
        public:
           // some constructor
           std::string save(MiddleClass & value) {
               std::string result;
    
               Save saver(result);
               saver.save(value);
    
               return result;
           }
    };
    

    Which can be easily "ported" to Python!