CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 3 of 3 FirstFirst 123
Results 31 to 45 of 45
  1. #31
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: std::string and contiguous memory?

    Quote Originally Posted by sszd
    It has been guaranteed in the present by the fact that all known implementations of std::string do guarantee these things, and the latest C++ standard that was approved last year guarantee that all future implementations will be compliant as well, so it is overly paranoid to assume otherwise.
    I think he's right here. You're not writing code to be that may be compiled with an older standard library implementation that may be unknown to you, so just check that what you have satisfies the assumption (it probably does). If so, all is well: go ahead and use &s[0] even if the standard library implementation was written at a time when the current guarantees did not exist.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  2. #32
    Join Date
    Apr 1999
    Posts
    27,449

    Re: std::string and contiguous memory?

    Reviewer: I'm not claiming that what you did won't work, only that it's unnecessarily convoluted. I am concerned about the impact on maintenance and what junior engineers are learning.
    Why does the reviewer think the other programmers are ignorant or can't simply look up this information? What the reviewer is stating sounds like projection -- he/she has a problem with it, so it must mean that others will have a problem with it. Unless you're using convoluted and obfuscated C coding in a C++ program, a reviewer should (or would) never say this, since IMO this is an indictment of the other programmers.

    If these programmers don't know that vector is contiguous, then what other aspect of the standard library do they not know? Are you allowed to use vectors as a replacement for new[]/delete[]? How about usage of algorithms? Function objects? Might as well have the reviewer list them, so you don't waste your time writing code that uses these idioms.

    Regards,

    Paul McKenzie

  3. #33
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: std::string and contiguous memory?

    Quote Originally Posted by laserlight View Post
    I think he's right here. You're not writing code to be that may be compiled with an older standard library implementation that may be unknown to you, so just check that what you have satisfies the assumption (it probably does). If so, all is well: go ahead and use &s[0] even if the standard library implementation was written at a time when the current guarantees did not exist.
    Unfortunately, my real world experience kind of makes me feel the same way. Yes, it is wrong, but let's face it, it works, and it costs less.

    What I suggest you do though, rather than doing an ugly const_cast, or an undefined &str[0]/&*str.begin(), is to use a non-member "data" function. C++11 defined non-member functions such as begin/end that could be used on either containers or with static arrays. Why not just do the same thing with a data function? Here is what I have in mind:

    Code:
    #include <vector>
    #include <iostream>
    #include <string>
    #include <array>
    #include "data.h"
    
    int main() {
            std::vector<int> vec1(10);
      const std::vector<int> vec2(10);
            char* p1 = "blablabla";
      const char* p2 = "blablabla";
            char a1[10] = "blablabla";
      const char a2[10] = "blablabla";
            std::string s1 = "blablabla";
      const std::string s2 = "blablabla";
            std::array<int, 3> ar1 = {1, 2, 3};
      const std::array<int, 3> ar2 = {1, 2, 3};
    
      std::cout << *data(vec1) << std::endl;
      std::cout << *data(vec2) << std::endl;
      std::cout << *data(p1) << std::endl;
      std::cout << *data(p2) << std::endl;
      std::cout << *data(a1) << std::endl;
      std::cout << *data(a2) << std::endl;
      std::cout << *data(s1) << std::endl;
      std::cout << *data(s2) << std::endl;
      std::cout << *data(ar1) << std::endl;
      std::cout << *data(ar2) << std::endl;
    }
    With this approach, you have access to a generic/portable "data" method, that works for any compatible container-like object. The advantage is the developper doesn't have to worry since the public interface of "data" is: "I guarantee I work. Don't worry about it".

    To implement this, you have two options:

    The first one, the easy one:

    Code:
    //Generic container
    template<typename T>
    typename T::pointer data(T& input)
    {
      return const_cast<typename T::pointer>(input.data());
    }
    
    //Generic const_container
    template<typename T>
    typename T::const_pointer data(const T& input)
    {
      return input.data();
    }
    
    //Generic (const) pointer/array
    template<typename T>
    T* data(T* input)
    {return input;}
    By adding that const_cast, it makes sure the call works for either generic containers (vector/array), as well as strings classes. Yay!

    I'd recommend this actually doing this though:

    Code:
    //Generic container
    template<typename T>
    typename T::pointer data(T& input)
    {
      return input.data();
    }
    
    //Generic const_container
    template<typename T>
    typename T::const_pointer data(const T& input)
    {
      return input.data();
    }
    
    //basic_string forward
    namespace std{
    template<typename C, typename T, typename A>
    class basic_string;
    }
    
    //data for basic_string
    template<typename C, typename T, typename A>
    typename std::basic_string<C, T, A>::pointer data(std::basic_string<C, T, A>& input)
    {
      return const_cast<typename std::basic_string<C, T, A>::pointer>(input.data());
    }
    
    //data for const basic_string
    template<typename C, typename T, typename A>
    typename std::basic_string<C, T, A>::const_pointer data(const std::basic_string<C, T, A>& input)
    {
      return input.data();
    }
    
    //Generic (const) pointer/array
    template<typename T>
    T* data(T* input)
    {return input;}
    This is a bit more convoluted, but it separates the implementation for string_types. This can be useful if you want to track down all data calls to [|s|s|u13|u32]string's

    EDIT: I just remembered you aren't using C++11, so you can replace the container's ".data" with ".empty? null, &[0];"
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  4. #34
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: std::string and contiguous memory?

    Quote Originally Posted by monarch_dodra
    With this approach, you have access to a generic/portable "data" method, that works for any compatible container-like object. The advantage is the developper doesn't have to worry since the public interface of "data" is: "I guarantee I work. Don't worry about it".
    Nice, but...

    Quote Originally Posted by monarch_dodra
    EDIT: I just remembered you aren't using C++11, so you can replace the container's ".data" with ".empty? null, &[0];"
    There are containers for which &x[0] is valid, but which do not store the elements of x contiguously, e.g., std:eque (which does not have a data() member function in C++11). In such a case, this workaround would not result in a compile error, i.e., this non-member data() would not actually guarantee that it works.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  5. #35
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: std::string and contiguous memory?

    Why does he think using std::vector is liable to be a maintenance problem?
    It's hardly a lot of extra code to write.

    Code:
    // Unsafe way
    std::string text("Some text");
    ...
    Function(const_cast<char*>(text.c_str()));
    
    // Safe way
    // Safe C string generator.
    class SafeCString
    {
    public:
    
        SafeCString(const std::string& text)
        {
            data.assign(text.c_str(), text.c_str() + text.size() + 1);
        }
    
        char* operator()()
        {
            return &data[0];
        }
    
    private:
    
        std::vector<char> data;
    };
    
    std::string text("Some text");
    ...
    Function(SafeCString(text)());
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  6. #36
    Join Date
    May 2009
    Posts
    2,413

    Re: std::string and contiguous memory?

    Quote Originally Posted by sszd View Post
    That’s why I used a vector. My co-worker is very persistent though, so I just needed some proof.
    I think you're both wrong. There's no reason to assume anything about the internals of vector or string really. Use them at the level of abstraction they were designed for. Don't break encapsulation in ordinary code just because you can.

    So create an ordinary char array, copy the string content to it and pass it to the function? That's the proper C solution to a C problem and it's guaranteed to be correct.

  7. #37
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: std::string and contiguous memory?

    Quote Originally Posted by nuzzle
    I think you're both wrong. There's no reason to assume anything about the internals of vector or string really. Use them at the level of abstraction they were designed for. Don't break encapsulation in ordinary code just because you can.
    I linked to Herb Sutter's blog post on this earlier, admittedly for a different reason, but the blog post itself was about whether using &v[0] for a std::vector v violates the abstraction: Cringe not: Vectors are guaranteed to be contiguous. He concludes that by design, it doesn't.

    EDIT:
    Consequently, the same idea applies for the guarantee of contiguous storage of the contents of basic_string in C++11.

    Quote Originally Posted by nuzzle
    So create an ordinary char array, copy the string content to it and pass it to the function? That's the proper C solution to a C problem and it's guaranteed to be correct.
    You will then have to do manual memory management. Not the end of the world, but why do that when there's std::vector, or post-C++11 (or with suitable knowledge that it is safe) std::string?
    Last edited by laserlight; June 29th, 2012 at 04:47 AM.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  8. #38
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,725

    Re: std::string and contiguous memory?

    One question though, is data() guaranteed to return a null terminated string, or is that also implementation dependent
    Not in the old standard ... in C+11 data() is guaranteed to return a null terminated string.
    c_str() is guaranteed in both versions.

  9. #39
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: std::string and contiguous memory?

    Quote Originally Posted by laserlight View Post
    Nice, but...


    There are containers for which &x[0] is valid, but which do not store the elements of x contiguously, e.g., std:eque (which does not have a data() member function in C++11). In such a case, this workaround would not result in a compile error, i.e., this non-member data() would not actually guarantee that it works.
    Crap

    There goes my beautiful design
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  10. #40
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: std::string and contiguous memory?

    [doublepost]
    Last edited by monarch_dodra; June 29th, 2012 at 07:19 AM.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  11. #41
    Join Date
    Nov 2003
    Posts
    1,902

    Re: std::string and contiguous memory?

    >> I would like to say I have no intention on changing the code that I have written based on our conversation, unless he goes to management and tries to force me to see things his way
    Be mindful of the "office politics" in play here. You don't want to set an unfavorable perception of yourself in other's eyes.

    >> The interface is non-const. There is no guarantee that the interface won't modify the non-const buffer. Therefore there is no argument for using const_cast that could possibly hold water.
    There is no debate outside of that. Using const_cast<> in this case is just garbage. Once that fact is accepted, then move on to "how to do it right". If that fact won't be accepted, move on. Not much you can do besides laying down that facts (what the standard says), and the opinions of yourself and other experts in the field like Scott Meyers and Herb Sutter.

    gg
    Last edited by Codeplug; June 29th, 2012 at 09:57 AM.

  12. #42
    Join Date
    May 2009
    Posts
    2,413

    Re: std::string and contiguous memory?

    Quote Originally Posted by laserlight View Post
    I linked to Herb Sutter's blog post on this earlier, admittedly for a different reason, but the blog post itself was about whether using &v[0] for a std::vector v violates the abstraction:
    Herb Sutter makes it a special point that he's in disagreement with Andy Koenig so I guess I side with the latter.

    My point is that you have a choise. You don't have to use every aspect of an interface. Just because it's there doesn't mean you have to use it. It's better to stay away from things that are shaky, questionable or just downright ugly in general.

    As of C++ 11 vector and string finally have certain firm guarantees for how memory is handled internally. But to me that's a big yawn because I'm never going to make use of this anyway. Not even if Herb Sutter claims it's a proper part of a vector or string abstraction. I, and possibly Andy Koenig, still don't think it is. Especially not if the only motivation is that it belongs there because it is there. And note that the OP is using pre-version 11 C++ where the situation isn't that clear-cut.

    In my view the OP should suggest an adapter class to convert a string into a suitable char array in a way that doesn't make any assumptions on the internals of string or vector at all. That will undisputably work. And this should be presented as a first step towards a more thorough interface to that API library that's used.

    That's the constructive thing to do. Getting out of this silly conflict where both sides are wrong and start improving the program together. I'm not against deep discussions about technical detail but sometimes they become all trees that prevent you from seeing the wood.
    Last edited by nuzzle; June 30th, 2012 at 02:07 AM.

  13. #43
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: std::string and contiguous memory?

    Quote Originally Posted by JohnW@Wessex View Post
    Why does he think using std::vector is liable to be a maintenance problem?
    It's hardly a lot of extra code to write.
    Truth. however, it lacks the "other" class, SafeMutableCString, if the point is to mutate the string:

    Code:
    struct SafeMutableCString
    {
    public:
        explicit SafeMutableCString(std::string& str) //NON CONST THIS TIME
          : m_str(str)
        {
            data.assign(m_str.c_str(), m_str.c_str() + str.size() + 1);
        }
    
        operator char*() //I changed this from char* operator()
        {
            return &data[0];
        }
    
        ~SafeMutableCString() //Destructor writes back to string
        {
          m_str = &data[0];
        }
    
    private:
        std::string& m_str;
        std::vector<char> data;
    };
    BTW, I think the design is better with an explicit destructor, but implicit cast. The usage becomes more transparent, and I don't think there is any potential for wrong usage (since the constructor is explicit, and the ONLY point in creating the struct is to cast it anyways) :

    Code:
    void foo(char * p)
    {
      strcpy(p, "hello world!");
    }
    
    int main()
    {
      std::string text("Some text containing lots of letters");
      foo(SafeMutableCString(text));
      std::cout << text << std::endl;
    }
    Again, I think the strength in such a design is not the internals, but the public interface. In the long run, who cares how SafeMutableCString is written, as long as the coder can use it without worry. If your reviewer wants to replace the implementation with const_cast for efficiency reasons, then power to him. You, on the other hand, are using a method with an interface certified safe.
    Last edited by monarch_dodra; June 30th, 2012 at 07:45 AM.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  14. #44
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: std::string and contiguous memory?

    Quote Originally Posted by nuzzle
    You don't have to use every aspect of an interface. Just because it's there doesn't mean you have to use it. It's better to stay away from things that are shaky, questionable or just downright ugly in general.
    I agree, but with respect to C++11, the &s[0] solution for std::string s is not shaky, questionable or downright ugly (a little ugly?). With respect to C++03, the &v[0] solution for an intermediate std::vector v is not shaky or questionable, but I concede that it is downright ugly compared to your suggestion of an adapter class... but then it could be used to implement the adapter class (like what JohnW@Wessex and monarch_dodra have been posting about recently).

    Quote Originally Posted by nuzzle
    Especially not if the only motivation is that it belongs there because it is there.
    Sutter's assertion is that it is there because it belongs there and considering that the lack thereof was considered a defect in C++98, that makes sense to me. If it had been in C++98 rather than amended in C++03, then your argument might hold water.

    Quote Originally Posted by nuzzle
    In my view the OP should suggest an adapter class to convert a string into a suitable char array in a way that doesn't make any assumptions on the internals of string or vector at all. That will undisputably work.
    If there is a guarantee, then there is no assumption. It will undisputably work.

    Where the assumption comes in would be if sszd goes with the &s[0] solution for a std::string s, with the knowledge that the standard library implementation does not conform to C++11, but happens to use contiguous storage. It may be a practical solution, but it is still an assumption, not a guarantee.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  15. #45
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Re: std::string and contiguous memory?

    Quote Originally Posted by monarch_dodra View Post
    BTW, I think the design is better with an explicit destructor,
    I agree. That was a mistake on my part; I normally always make single parameter constructors explicit.
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

Page 3 of 3 FirstFirst 123

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured