2

I'm developing a "MemRef" class to use in place of std::string, to cut down on const string copying by passing around pointers instead. A MemRef object consists simply of a char* ptr and an int len.

I want to make it possible to call the function foo(const string&) as foo(my_memref), by defining a method to convert a MemRef into a std::string. What I've read about "conversion constructors" seems to only address the issue of converting from some other data type to my class, rather than the other way around. I've also read that conversion constructors are often more trouble than they're worth.

Is there a way to define an implicit "convert to some other type" method in a class, such that I can write (e.g.) display_string(my_memref)?


UPDATE: Here's the current attempt:

// This is a "cast operator", used when assigning a MemRef to a string
MemRef::operator std::string() const {
    // construct a string given pointer and length
    std::string converted(ptr_, len_);
    return converted;                                                           
} 

And here's the use:

:
const string foo("ChapMimiReidAnn");
MemRef c(foo.c_str(), 4);
begin_block(c);
:

void
begin_block(const string& s) {
    cout << "begin_block('" << s << "')" << endl;
}

But here's the error:

c++ -c -pg -O0 -fno-strict-aliasing --std=c++11  -arch x86_64  -I/Users/chap/private/WDI/git -I/Users/chap/private/WDI/git/include -I/usr/local/mysql/include -I/usr/local/include   memref_test.cpp
c++ -c -pg -O0 -fno-strict-aliasing --std=c++11  -arch x86_64  -I/Users/chap/private/WDI/git -I/Users/chap/private/WDI/git/include -I/usr/local/mysql/include -I/usr/local/include   MemRef.cpp
c++ -o memref_test memref_test.o MemRef.o -L/usr/local/mysql/lib -lmysqlclient -pg 
Undefined symbols for architecture x86_64:
  "MemRef::operator std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >() const", referenced from:
      _main in memref_test.o
Chap
  • 3,649
  • 2
  • 46
  • 84

2 Answers2

3

What you want to do is create a cast operator to std::string in MemRef:

class MemRef {
public:
    ...
    operator std::string() {
        std::string stringRepresentationOfMemRef;
        ...
        ...
        return stringRepresentationOfMemRef;
    }
    ...
};
greken
  • 89
  • 3
  • So, would this require my writing `display_string(static_cast(my_memref))`? – Chap Nov 23 '13 at 00:50
  • No, as long as the conversion operator isn't marked `explicit` it can be used for implicit conversions, and `display_string(my_memref)` will work. The downside to this way is it will allocate and copy the string data every time it's used. – aschepler Nov 23 '13 at 01:03
  • @aschepler: Although there's no way around that, really, is there? If display_string requires a string reference, I need to fabricate a string. – Chap Nov 23 '13 at 02:32
  • @aschepler I'm having trouble making this solution work. I appended my work to the original post, along with the compiler error. – Chap Nov 23 '13 at 03:34
  • 1
    @Chap That's the way to do that. The error you get is from the linker, not the compiler. That means you have provided it with the declaration of the conversion operator but not the implementation. Are you sure your MemRef.cpp is compiled and linked with the rest? – greken Nov 23 '13 at 09:13
  • AFAICT, it is. (I updated the post to show the compile and link invocations.) Is it, rather, a signature mismatch? – Chap Nov 23 '13 at 17:49
  • Can you please include the definition of `operator std::string() const` from your header file? – NicholasM Nov 23 '13 at 20:08
  • Sorry to say I did not track the entire path to my solution -- I don't know if it was related to the error I showed above, but eventually it came down to my misusing the 'inline' keyword on a friend function (see http://stackoverflow.com/q/20168819/522385). – Chap Nov 25 '13 at 00:15
1

Something like the code below should do the trick. The problem though is that this code is not thread safe. When passing by value a simple cast overload will do the trick but passing by reference is a little trickier since you need to manage the lifetime of the object so that any references (including transitive references) are valid.

#include <stdio.h>
#include <memory.h>
#include <string>

class MyClass
{
public:
  MyClass()
  {
    m_innerString = "Hello";
  };


  operator std::string &()
  {
    return m_innerString;
  }
private:
    std::string m_innerString;
};

void testMethod(std::string &param)
{
  printf("String: %s", param.c_str());
}

int main(int argc, char *argv[])
{
  MyClass testClass;

  testMethod(testClass);
}

AFAIK it isn't really an easy way to do such a thing in a way that is thread safe since you will never know the lifetime of the string object that is being referenced. You might however be able to arrive at some sort of solution by using thread local storage and maintaining a separate string instance for each thread.

Nick Weedon
  • 441
  • 5
  • 10
  • It's treacherous enough even without being used in a multi-thread environmnet! But I'm using these objects to refer to pieces of an input buffer, and I'm not going to expose MemRefs in the API (hence my desire to convert MemRefs to strings). – Chap Nov 23 '13 at 00:54
  • This is entirely thread-safe. Unless you use the same `MyClass` object from multiple threads, which is the case for most data types. – aschepler Nov 23 '13 at 01:05
  • Actually as you mention it isn't really correct for me to say that there is a possible threading issue. I think that what I meant to say is that there is really a more general issue here if there are external references held to m_innerString and you attempt to change its contents. This would be an issue in a multithreaded process but also in a single threaded process. Ideally it would be good if a copy of the string could be returned but the overload signature does not allow this. – Nick Weedon Jan 11 '14 at 10:46