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
4
  • Take care when implementing COW behavior, it's a tricky thing to get it working correctly. Commented Nov 23, 2013 at 0:20
  • 1
    It's really foo(string&); and not foo(const string&);? Commented Nov 23, 2013 at 0:20
  • @aschepler: you're correct, should be const string&. Commented Nov 23, 2013 at 0:44
  • 1
    This looks like it should work. The next thing to check is the output of nm memref_test.o and nm MemRef.o. Commented Nov 24, 2013 at 18:44

2 Answers 2

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;
    }
    ...
};
Sign up to request clarification or add additional context in comments.

8 Comments

So, would this require my writing display_string(static_cast<std::string>(my_memref))?
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: Although there's no way around that, really, is there? If display_string requires a string reference, I need to fabricate a string.
@aschepler I'm having trouble making this solution work. I appended my work to the original post, along with the compiler error.
@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?
|
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.

3 Comments

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).
This is entirely thread-safe. Unless you use the same MyClass object from multiple threads, which is the case for most data types.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.