printf question with a const char* variable
Asked Answered
S

3

6

I am stuck in a printf problem. I would appreciate if I can get some help here: In the below code, I can see the font family get displaced correctly in first printf(), but if I set it to variable, i only get an empty string. How can I put it in a variable and have the right values? I just don't want to type 'font.family().family().string().utf8().data()' everywhere?

I did this in the same method:

void myMethod() {
      const char* fontFamily = font.family().family().string().utf8().data();
      // get displayed correctly
      printf ("drawText1 %s \n", font.family().family().string().utf8().data());
      // get an empty string
      printf ("drawText2 %s \n", fontFamily);
}

And the signature of 'data()' is

class CString {
public:
    CString() { }
    CString(const char*);
    CString(const char*, unsigned length);
    CString(CStringBuffer* buffer) : m_buffer(buffer) { }
    static CString newUninitialized(size_t length, char*& characterBuffer);

    const char* data() const;
 //...

}

The signature of utf8() is

class String {
 CString utf8() const;
}

Thank you.

Schmitt answered 5/3, 2010 at 21:42 Comment(5)
What is this font library? C++ has no such thing. Maybe try including the type returned by data(). On a side note, any reason not to use std::string/std::cout?Oestrone
It would help to know the signature of the .data() method.Kitts
And family.string() returns a temporary object of type CString?Onieonion
What happened to the Law of Demeter?Thermomotor
We most likely need more details about data(). Can you post the full implementation?Etem
T
4

Something in the chain of font.family().family().string().utf8().data() is returning a temporary object. In your first printf, the temporary object doesn't go out of scope until the printf returns. In the second printf, the temporary has been destroyed after the pointer assignment was made, and the pointer is now invalid. You're seeing a classic example of "undefined behavior".

There are two ways to fix this. Either make a copy of the data before the temporary gets destroyed, or make a reference to the temporary. The copy is probably easiest and clearest, as long as the class has a copy operator. Assuming that utf8() generates a temporary CString, this would be

CString fontFamily = font.family().family().string().utf8();
printf ("drawText2 %s \n", fontFamily.data());
Tisatisane answered 5/3, 2010 at 21:46 Comment(11)
This is wrong. Temporaries are guaranteed to hang around for as long as need be (more or less).Reiner
A reference to a temporary is guaranteed, but a pointer to some internal data member? I think not.Tisatisane
There are no pointers in the quoted code. "Internal" pointers will be taken care of by the c++ constructor/destructor mechanism.Reiner
@Neil, the data() function is returning a char *, that is the pointer I am referring to. utf8() is probably returning a temporary CString, although that is just a guess.Tisatisane
@Mark It doesn't matter. Assuming a CString has a reasonable copy constructor the temporary will remain valid. This is a guarantee made by the C++ language standard.Reiner
@Neil Butterworth: What are you talking about? It is perfectly possible that any of the intermediate calls returns a temporary. This temporary will be killed immediately after the initialization of fontFamily (this leaving fontFamily hanging in the air). There are no guarantees in the language that would extend the lifetime of the temporary. Where did you get that idea? The only similar-sounding thing in C++ is guaranteed for references specifically, but we have no references in this example.Gand
@AndreyT A temporary must live to the end of the expression it is part of.Reiner
@Neil Butterworth: Apparently you misunderstood. Mark must be talking about the second printf - the one that "doesn't work". The expression in this case is used to initialize a const char* fontFamily pointer. Once the initialization is over, the temporary is destroyed. And fontFamily pointer is left hanging in the air. Yet the OP is trying to print the string it is supposedly pointing to. The result is UB for the second printf. The first printf is indeed OK, becuse the whole thing is one expression.Gand
@AndreyT Mark may have been talking about any number of things - my comment was about what he actually said. He nowhere mentioned the second printf.Reiner
@Neil Butterworth: Well, the topic of this question is (as it is clearly expressed by the OP): why the second printf doesn't work as expected, while the first one does.Gand
@AndreyT and @Neil, thanks for making me see how ambiguous my language was. I'll clean up the answer.Tisatisane
C
1

You are caching a pointer that resides in the temporary returned by utf8() (as Mark and Neil have argued about). You'll have to change fontFamily to either a CString or const CString & to keep the result from utf8() in scope.

Consequence answered 5/3, 2010 at 22:19 Comment(0)
R
0

The call to data() (assuming it is called on a std::string) does not necessarily return a null-terminated string. You almost certainly want c_str(), which is defined to do so.

Reiner answered 5/3, 2010 at 21:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.