how to avoid temporaries when copying weakly typed object

Posted by Truncheon on Stack Overflow See other posts from Stack Overflow or by Truncheon
Published on 2010-04-18T20:08:41Z Indexed on 2010/04/18 21:03 UTC
Read the original article Hit count: 185

Hi.

I'm writing a series classes that inherit from a base class using virtual. They are INT, FLOAT and STRING objects that I want to use in a scripting language. I'm trying to implement weak typing, but I don't want STRING objects to return copies of themselves when used in the following way (instead I would prefer to have a reference returned which can be used in copying):

a = "hello ";
b = "world";
c = a + b;

I have written the following code as a mock example:

#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>

std::string dummy("<int object cannot return string reference>");

struct BaseImpl
{
    virtual bool is_string() = 0;
    virtual int get_int() = 0;
    virtual std::string get_string_copy() = 0;
    virtual std::string const& get_string_ref() = 0;
};

struct INT : BaseImpl
{
    int value;

    INT(int i = 0) : value(i)
    {
        std::cout << "constructor called\n";
    }
    INT(BaseImpl& that) : value(that.get_int())
    {
        std::cout << "copy constructor called\n";
    }
    bool is_string() { return false; }
    int get_int()
    {
        return value;
    }
    std::string get_string_copy()
    {
        char buf[33];
        sprintf(buf, "%i", value);
        return buf;
    }
    std::string const& get_string_ref()
    {
        return dummy;
    }
};

struct STRING : BaseImpl
{
    std::string value;

    STRING(std::string s = "") : value(s)
    {
        std::cout << "constructor called\n";
    }
    STRING(BaseImpl& that)
    {
        if (that.is_string())
            value = that.get_string_ref();
        else
            value = that.get_string_copy();

        std::cout << "copy constructor called\n";
    }
    bool is_string() { return true; }
    int get_int()
    {
        return atoi(value.c_str());
    }
    std::string get_string_copy()
    {
        return value;
    }
    std::string const& get_string_ref()
    {
        return value;
    }
};

struct Base
{
    BaseImpl* impl;

    Base(BaseImpl* p = 0) : impl(p) {}
    ~Base() { delete impl; }
};

int main()
{
    Base b1(new INT(1));
    Base b2(new STRING("Hello world"));
    Base b3(new INT(*b1.impl));
    Base b4(new STRING(*b2.impl));

    std::cout << "\n";
    std::cout << b1.impl->get_int() << "\n";
    std::cout << b2.impl->get_int() << "\n";
    std::cout << b3.impl->get_int() << "\n";
    std::cout << b4.impl->get_int() << "\n";
    std::cout << "\n";
    std::cout << b1.impl->get_string_ref() << "\n";
    std::cout << b2.impl->get_string_ref() << "\n";
    std::cout << b3.impl->get_string_ref() << "\n";
    std::cout << b4.impl->get_string_ref() << "\n";
    std::cout << "\n";
    std::cout << b1.impl->get_string_copy() << "\n";
    std::cout << b2.impl->get_string_copy() << "\n";
    std::cout << b3.impl->get_string_copy() << "\n";
    std::cout << b4.impl->get_string_copy() << "\n";

    return 0;
}

It was necessary to add an if check in the STRING class to determine whether its safe to request a reference instead of a copy:

Script code:

a = "test";
b = a;

c = 1;
d = "" + c; /* not safe to request reference by standard */

C++ code:

STRING(BaseImpl& that)
{
    if (that.is_string())
        value = that.get_string_ref();
    else
        value = that.get_string_copy();

    std::cout << "copy constructor called\n";
}

If was hoping there's a way of moving that if check into compile time, rather than run time.

© Stack Overflow or respective owner

Related posts about c++

Related posts about polymorphism