Hacker News new | past | comments | ask | show | jobs | submit login

It won't be as good as Haskell for memory safety. For example, this program, using only C++11 idioms, crashes:

    #include <iostream>
    #include <vector>

    int main() {
        std::vector<std::string> v;
        v.push_back(std::string("Hello"));
        v.push_back(std::string("there"));
        for (auto ii = v.begin(), ie = v.end(); ii != ie; ++ii) {
            v.clear();
            std::cout << *ii << std::endl;
        }
        return 0;
    }
Preventing this sort of thing requires strong guarantees about aliasing (to ensure that "v" can't alias the vector being iterated over), which the C++ type system can't help you with.



“C++11 idioms” include a preference for immutability, which leads to natural factorings. You don’t have to worry about things like iterator invalidation that way.

    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <vector>
    using namespace std;

    template<class T>
    void print(const T& v) {
      copy(begin(v), end(v), ostream_iterator<string>(cout, "\n"));
    }

    int main(int argc, char** argv) {
      vector<string> v{"Hello", "there"};
      print(v);
    }
Also, Haskell is only so safe—at work we’ve taken to rejecting non-total functions in review, because they cause more hassle than they’re worth. By non-total, I refer more to “error” than non-termination, of course.


"const" doesn't help you in the presence of aliasing:

    #include <iostream>
    #include <vector>

    template<typename T,typename U>
    void print(const T& v, U& w) {
        for (auto ii = v.begin(), ie = v.end(); ii != ie; ++ii) {
            w.clear();
            std::cout << *ii << std::endl;
        }
    }

    int main() {
        std::vector<std::string> v;
        v.push_back(std::string("Hello"));
        v.push_back(std::string("there"));
        print(v, v);
        return 0;
    }
In general there are lots of ways to get non-const access to const data. You'd need a sophisticated form of whole-program alias analysis to eliminate the unsafety here. (Even if you didn't have the second "U& w" parameter, there are other potential ways that "print" could get non-const access to "v"; global variables, TLS, by accessing a member of "v", etc.)


I don't disagree about aliasing, but a print function shouldn't be taking ref to a non-const anything anyways, it should have no need to mutate the vector. You can't clear through a ref to const. Your general point holds but I would say I have probably written/found very few aliasing bugs in C++ over the years, it just doesn't seem to arise often, perhaps your experience differs. Alas there are few ways to prevent dedicated folks from writing really ill-advised code.


I see what you’re getting at. Still, if you do the sensible things—immutability, encapsulation of shared state, &c.—then you’re most of the way to safety. I would that C++ made it easier, though; that’s the real issue.


That does not look like C++11. You don't use initializer lists. You don't use new-style for-loops. I'll give you that those don't add much to safety, though. A functional style with Boost ranges, adapters and algorithms do, however. I clearly write in the post that you shouldn't use for-loops. Use ranges and pipes.


I don't see how Boost algorithms provide the aliasing guarantees you need to avoid invalidating iterators. It's a very difficult problem. Even if you use a library to pipe instances of your custom string class to cout and you trust that library, the method or function that sends your custom string class to cout could perform arbitrary mutations, which would invalidate the iterator.

For example:

    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <vector>

    class mystring {
    public:
        std::string m_s;
        mystring(const std::string &s) : m_s(s) {}
    };

    std::vector<mystring> v;

    void operator<<(std::ostream &out, const mystring &ms) {
        v.clear();
        out << ms.m_s;
    }

    int main() {
        v.push_back(mystring(std::string("Hello")));
        v.push_back(mystring(std::string("world")));
        std::copy(v.begin(), v.end(), std::ostream_iterator<mystring>(std::cout, "\n"));
        return 0;
    }




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: