Obay Abd-Algader
Obay Abd-Algader

Reputation: 1277

how to create move constructor that takes const char* "string literal"

I want to create a move constructor that takes string literal, and then move that c string to a member pointer. The best solution I could write is giving a warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings] CTextBlock cctb("move(H)"); ^ the code:

#include <iostream>
using namespace std;

class CTextBlock
{
public:
    CTextBlock(char* &&text)//move constructor
    {
        pText = text;
    }
private:
    char *pText;
};
int main()
{
    CTextBlock cctb("move(H)"); //WARNING
    return 0;
}

Upvotes: 1

Views: 2691

Answers (3)

Kerrek SB
Kerrek SB

Reputation: 477238

A constructor that gets reasonably close to allowing only literals can be realized as a template:

#include <cstddef>
#include <assert>

struct X
{
    char const * str;
    std::size_t len;

    template <std::size_t N>
    X(char const (&a)[N]) : str(a), len(N - 1)
    {
        assert(a[len] == '\0');   // true for string literals
    }
};

It's not fool-proof, though, since it will also bind to named character arrays, and the length computation is dubious if your string also contains null values. But if you're trying to avoid accidental use of dynamic values (e.g. in an algorithm that builds strings from expressions and literal strings), this is fairly useful.

Upvotes: 0

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153915

First off, the type of string literals is char const[N] (for a suitable constant N). This array can be assigned to a char const* in which case it will decay into a pointer to the first element. It cannot be converted to a char*. Prior to C++11 the conversion to char* was allowed to deal with existing code which wasn't const-correct (e.g., because it started as C code before C got const). This conversion was removed for C++11.

Question is what you actually try to achieve, though: string literals are immutable and persist for the entire life-time of the program. You can just keep as many pointers to them as you want and there is no point in moving pointers as these are entirely cheap to copy.

In your question you indicate that you want to create a move constructor but move constructors take an rvalue reference of the class they are for, e.g., this would be a move constructor for you class:

CTextBlock::CTextBlock(CTextBlock&& other)
    : pText(other.pText) {
    other.pText = 0;
}

(your class doesn't show any ownership semantics for the pointer pText in which case move construction doesn't really make much sense; the above code assumes that there is some ownership semantics and that a null pointer indicates that the object doesn't own anything).

Just because an argument is constrained to be an rvalue reference doesn't mean that function is a move constructor. All it implies is that the argument is an rvalue an it can reasonably be assume that it's current representation doesn't need to be retained. The string literal appears to be an rvalue because the the string literal is converted into a [temporary] pointer to the start of the array.

Upvotes: 3

Sam Varshavchik
Sam Varshavchik

Reputation: 118415

A string literal is a const char *. This is true whether or not it's used as an lvalue or an rvalue.

If you review your code again, you are, therefore, attempting to store a const char * into a char *, and that's where your compiler diagnostic is coming from. Your move constructor is taking an rvalue reference to a char *, and not a const char *. Change it to a const char *, and change the pText class member to a const char *, and what you're trying to do should work.

Upvotes: -2

Related Questions