0

Move semantics is well-known topic in C++:What is move semantics?.

Immutability is another important concept in programming.

I want to combine the 2 to make efficient immutable objects.

From the above link, I create a simple string class:

The main point is in the 2 "append" methods.

#include <iostream>
#include <cstring>
#include <algorithm>

class string {
    char *data;

public:

    string(const char *p) {
        size_t size = std::strlen(p) + 1;
        data = new char[size];
        std::memcpy(data, p, size);
    }

    ~string() {
        delete[] data;
    }

    string(const string &that) {
        size_t size = std::strlen(that.data) + 1;
        data = new char[size];
        std::memcpy(data, that.data, size);
    }

    string(string &&that) {
        data = that.data;
        that.data = nullptr;
    }

    // Copied from the link above but make the object no longer immutable, so discard it
    // string& operator=(string that) {
    //     std::swap(data, that.data);
    //     return *this;
    // }

    // "this" is a normaly pointer, but we show it as a rvalue reference
    string& append(/*string &&this, */ const char *p) {
        std::cout << "move" << std::endl;
        size_t size = std::strlen(data) + std::strlen(p) + 1;
        char *tmpData = new char[size];
        std::strcpy(tmpData, data);
        std::strcat(tmpData, p);

        delete[] data;

        data = tmpData;

        return *this;
    }

    // "this" is a normaly pointer, but we show it as a reference
    string append(/*const string &this, */ const char *p) const {
        std::cout << "copy" << std::endl;
        return string(data, p); // use returned value optimization (copy elision)
    }

private:

    // Created to allow copy elision in "append copy"
    string(const char *start, const char *end) {
        size_t size = std::strlen(start) + std::strlen(end) + 1;
        data = new char[size];
        std::strcpy(data, start);
        std::strcat(data, end);
    }
};

int main() {

    string a("a");
    string b = a.append("...");
    string c = a.append("1...").append("2...");
    string d = string("s").append("1...").append("2...");

    return 0;
}

(The compiler discards "append copy" and only calls "append move".)

I know the code does not work as expected the idea is to be able to use move semantics with "this" pointer and the compiler able to choose among the 2 "append" methods. So the above program will work like this:

string b = a.append("...");

will call "append copy"

string c = a.append("1...").append("2...");

will call "append copy", then "append move"

string d = string("s").append("1...").append("2...");

will call "append move", then "append move"`

If anyone has some insight to make it possible, I am pleased to learn it.

  • 1
    You have to qualify the members like string& append(const char *p) && {...} – Öö Tiib Feb 11 '23 at 23:18
  • 3
    Immutability and move semantics are contradictory. Using a move operation (constructor/assignment operator) is expected to modify the moved-from object. Anyway, it is possible to do what you want - call different methods based on whether `*this` is lvalue or rvalue - using *ref-qualifiers*. See duplicate for more details. – Yksisarvinen Feb 11 '23 at 23:18
  • 1
    @Jean-LucDelarbre FYI, your "move" `append()` method can be greatly simplified using the same constructor the "copy" `append()` uses, eg: `string& append(/*string &&this, */ const char *p) { std::cout << "move" << std::endl; string tmp(data, p); std::swap(data, tmp.data); return *this; }` – Remy Lebeau Feb 11 '23 at 23:25
  • @Yksisarvinen you might want to link to the duplicate you are referring to – Remy Lebeau Feb 11 '23 at 23:26
  • @RemyLebeau Is the banner on top not visible enough? Just in case, the duplicate is here: https://stackoverflow.com/questions/8610571/what-is-rvalue-reference-for-this. – Yksisarvinen Feb 11 '23 at 23:35
  • @Yksisarvinen there was no banner visible yet when I posted that comment. – Remy Lebeau Feb 12 '23 at 00:38
  • @Yksisarvinen Ok in a strict way move-semantics and immutability are contradictory. But paractically what really bother me is to have an immutable object as long as I can get a reference on it... – Jean-Luc Delarbre Feb 12 '23 at 14:30

0 Answers0