Passing a string literal as a reference

I've been going through the tutorial and thought I had the grasp of references. I thought references were required to be an lvalue or a space in memory. e.g.,

int a; // located in in memory
int& ra = a; // ra is the exact same place in memory

ra =2;
std::cout << a;
std::cout << ra;

and it should show a has the value of 2 and ra has the value of 2. No problem here. a and ra are the same variable located in the same place in memory. They just have different names.

Now the code below from the tutorial. How can a string literal be passed as a reference? Where is its place in memory?

This code is also legal:

const int& ten = 10;

Is the compiler simply replacing the reference with the literal wherever it appears?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  // classes and default constructors
#include <iostream>
#include <string>
using namespace std;

class Example3 {
    string data;
  public:
    Example3 (const string& str) : data(str) {} // ***here's the line ***
    Example3() {}
    const string& content() const {return data;}
};

int main () {
  Example3 foo;
  Example3 bar ("Example");

  cout << "bar's content: " << bar.content() << '\n';
  return 0;
}
The memory of a string literal should not be changed, it is usually in the static part of your memory as far as I know.
Your Example3 constructor is copying the string literal into an std::string container called "data". So it no longer has anything to do with the string literal on line 16.

Hopefully that answers your question? Wasn't exactly sure what you meant by "replacing the reference".

If you want to pass the string literal "directly" (without constructing an std::string), the most common way is to pass the pointer to it.
1
2
3
4
5
6
7
8
9
#include <iostream>
void passing(const char* s)
{
    std::cout << s << std::endl; // ostream knows how to print string literals
}
int main()
{
    passing("hello");   
}
Last edited on
This code is also legal:

const int& ten = 10;

Is the compiler simply replacing the reference with the literal wherever it appears?
It creates a tmporary unnamed integer variable with value of 10. As constant references prolongs lifetime of referenced object, it is not destroyed right away.

Of course compiler car substitute any instances of ten with 10. If it can prove that it will not change visible behavior of program.
How can a string literal be passed as a reference? Where is its place in memory?

In the tutorial example a temporary std::string is constructed and passed to Example3 (const string& str) it's this temporary std::string that is passed to the copy constructor of the member variable data.

Note that only a const reference parameter can accept a literal in this way (as far as standard C++ is concerned.) And the temporary only lives for the duration of the expression it was required for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <cstring>
using namespace std;

namespace toy {
    namespace utils {
        char* copy(const char* in) {
            char* out = new char[strlen(in) + 1];
            strcpy(out, in);
            return out;
        }
    }
    class string {
    private:
        const char* psz;
    public:
        string() : psz(NULL) {
            cout << "string::string()\n";
        }
        string(const char* p) : psz(utils::copy(p)) {
            cout << "string::string(const char*)\n";
        }
        string(const string& s) : psz(utils::copy(s.psz)) {
            cout << "string::string(const string&)\n";
        }
        ~string() {
            cout << "string::~string()\n";
            delete [] psz;
        }
        const char* c_str() const {
            return psz;
        }
    };
} // end namespace toy

void write_msg(const toy::string& s) {
   cout << s.c_str() << "\n";
}

int main() {
    write_msg("hello world");

    return 0;
}


string::string(const char*)
hello world
string::~string()


Andy
Last edited on
PS Using my "toy" string with the Example3 I get (for no optimization)

string::string()
string::string(const char*)
string::string(const string&)
string::~string()
bar's content: Example
string::~string()
string::~string()


so the string literal is copied twice: once by string::string(const char*), when constructing the temporary, and again by string::string(const string&), to initialize the member data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// classes and default constructors
#include <iostream>
#include <string>

namespace toy {
    namespace utils {
        char* copy(const char* in) {
            char* out = new char[strlen(in) + 1];
            strcpy(out, in);
            return out;
        }
    }
    class string {
    private:
        const char* psz;
    public:
        string() : psz(NULL) {
            std::cout << "string::string()\n";
        }
        string(const char* p) : psz(utils::copy(p)) {
            std::cout << "string::string(const char*)\n";
        }
        string(const string& s) : psz(utils::copy(s.psz)) {
            std::cout << "string::string(const string&)\n";
        }
        ~string() {
            std::cout << "string::~string()\n";
            delete [] psz;
        }
        const char* c_str() const {
            return psz;
        }
    };
} // end namespace toy

std::ostream& operator<<(std::ostream& os, const toy::string& s) {
    return os << s.c_str();
}

class Example3 {
    toy::string data;
  public:
    Example3 (const toy::string& str) : data(str) {}
    Example3() {}
    const toy::string& content() const {return data;}
};

int main () {
  Example3 foo;
  Example3 bar ("Example");

  std::cout << "bar's content: " << bar.content() << '\n';
  return 0;
}
Last edited on
I think I understand. In cases of passing a literal as a reference, a temporary variable ( lvalue or actual place in memory) is created that holds the literal.

Thanks.
"Wasn't exactly sure what you meant by "replacing the reference"."

I meant sort of like what typedef does.

typedef unsigned int WORD;

wherever the compiler sees WORD it sees unsigned int.

I was wonder if

const int& ra = 10;

didn't work on the compiler level almost like a typedef, wherever it sees ra it sees 10. But As I understand it doesn't work like that. A temporary variable is created holding the value 10 and ra is that exact same variable but with a different name.
Now I'm wondering, if I compile this :

1
2
3
4
5
6
7
// my first program in C++
#include <iostream>

int main()
{
  std::cout << "Hello World!";
}


And search the executable file with a hex editor, I will find the string literal "Hello World!" in the code. That literal loads into memory with the code. That memory location cant be changed ( as far as I know). Thats the program. I wonder when you pass the reference to a string literal that you are passing the location or portion of program code that contains that string literal. It would makes sense that thats why its has to be const. It can't be changed, its part of the program. Is there really a temporary variable or is the reference just an alias to part of the program code that contains the literal?
Now I'm wondering, if I compile this : ...

And search the executable file with a hex editor, I will find the string literal "Hello World!"

Easy enough to do. You could even write your own hex dump tool!? (Actually, with bigger binaries it would better to search the file with grep or findstr.)

Yes, all string literals, along with other const data, are stored in a read-only segment of the executable image (gcc uses a .rodata section; MSVC a .rdata section.) That is, it's marked to be loaded into read-only memory.

C String literals: Where do they go?
http://stackoverflow.com/questions/2589949/c-string-literals-where-do-they-go

Is there really a temporary variable or is the reference just an alias to part of the program code that contains the literal?

Well, there will probably be a temp. But as MiiNiPaa has already said, if the compiler can work out that it's safe to swap e.g. 10 for ten (assuming const int& ten = 10;) when it will probably do it as an optiization. And as MiiNiPaa's example used a built-in type I feel it would be optimized out.

But with a class type you can see the temporary exists for the lifetime of main()

Enter main()
MyInt::MyInt()
Enter test()
i.value() returned 42
Leave test()
Leave main()
MyInt::~MyInt()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

class MyInt {
private:
    int val;
public:
    MyInt() : val(0) {
        cout << "MyInt::MyInt()\n";
    }
    MyInt(int v) : val(v) {
        cout << "MyInt::MyInt()\n";
    }
    ~MyInt() {
        cout << "MyInt::~MyInt()\n";
    }
    int value() const { return val; }
};

void test(const MyInt& i) {
    cout << "Enter test()\n";

    cout << "i.value() returned " << i.value() << "\n";

    cout << "Leave test()\n";
}

int main()
{
    cout << "Enter main()\n";

    const MyInt& ri = 42;

    test(ri);

    cout << "Leave main()\n";

    return 0;
}


Andy
Last edited on
> I will find the string literal "Hello World!" in the code

We would find the string literal "Hello World!" somewhere in memory (in 'storage')
The type of the string literal "Hello World!" is an array of 13 const char.
It has a static storage duration (it exists from beginning till the end of the program).


> I wonder when you pass the reference to a string literal that you are passing the
> location or portion of program code that contains that string literal.

The string literal is an object of type 'array of n const char'.
We can pass that object by reference; a reference is an alias, no copy is made.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

template < std::size_t N > // N is the size of the array
void foo( const char (&reference_to_array)[N] )
{
    // type of reference_to_array is 'reference to array of N const char'
    // it is an alias for an object of type 'array of N const char'
}

void bar( const char* pointer_to_const_char )
{
    // type of pointer_to_const_char is 'pointer to const char'
    // it contains an address that is passed by value
}

int main()
{
    const char (&literal_string)[13] = "Hello World!" ;
    // literal_string is an alias for on object of type 'array of 13 const char'

    foo( "Hello World!" ) ; // pass the array by reference

    // There is an implicit conversion from an array to a pointer
    // the result of the conversion is a pointer to the first element of the array.
    // this conversion is implicitly applied when an array is used in a context where
    // a pointers is required
    const char* pointer = "Hello World!" ;

    // implicitly apply the array to pointer conversion
    // and pass the resultant pointer by value
    foo( "Hello World!" ) ;

    std::cout << "Hello World!" ; // same as above (implicit array to pointer conversion)
    std::operator<< ( std::cout, "Hello World!" ) ; // same as above (conversion is implicit)
    std::operator<< ( std::cout, (const char*)"Hello World!" ) ; // same as above (conversion is explicit)
    std::cout << pointer ; // same as above
}
Topic archived. No new replies allowed.