Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
epswing
Nov 4, 2003

Soiled Meat
Really beginner question here, are these the same?

C++ code:
std::string s = "start";
std::string value = "hello";
s = value;
C++ code:
std::string s = "start";
std::string value = "hello";
s.assign(value);
I'm repeatedly setting s to a new value, but I'm not sure if I should be using the assignment operator, or the assign method. The assign method says it "Assigns a new value to the string, replacing its current contents", which I think is what I want. Both appear to "work" in the sense that s contains the value I want, but am I doing something wrong behind the scenes when using one rather than the other?

I guess a related question is, to clear a string value, can I safely set s = ""; or should I be doing s.clear();?

Edit: When googling, I see a lot of discussion surrounding "copy constructor vs assignment operator" but I don't think that's what I'm looking for.

epswing fucked around with this message at 18:55 on Apr 17, 2019

Adbot
ADBOT LOVES YOU

nielsm
Jun 1, 2009



They are completely identical.

The assign() function also lets you do substring extraction, assigning from raw character arrays, and more, but for straight assignment from one std::string to another there is zero difference.

epswing
Nov 4, 2003

Soiled Meat

nielsm posted:

They are completely identical.

The assign() function also lets you do substring extraction, assigning from raw character arrays, and more, but for straight assignment from one std::string to another there is zero difference.

Great, thanks!

Foxfire_
Nov 8, 2010

epalm posted:

I guess a related question is, to clear a string value, can I safely set s = ""; or should I be doing s.clear();?

These are pedantically slightly different.

s.clear(); Changes the size member of the string to 0 and maybe frees some storage
s = ""; Does everything s.clear() did, then copies from an array of char's until it reaches a 0x00 byte. That will happen immediately since the right hand side is an empty string.

In the 2nd one, there may be a length 1 constant global char array in memory somewhere depending on how your compiler implements/optimizes it. The first one never has that.

Kuule hain nussivan
Nov 27, 2008

I have another small thing which I just can't seem to figure out.

In my header file, I have the following...

code:
class Class {
public:
    stuff
private
    struct Struct {
        stuff
    }
Then in my code I'm trying to do the following...

code:
std::unordered_set<Struct, StructHash> set;
set.erase(someStruct);
This throws an error, which I think is because I need to overload the == operator for Struct. Problem is, I have no idea where to put it. I tried the following.



code:
class Class {
public:
    stuff
private
    struct Struct {
        stuff
	bool operator==(Struct c) { return attribute == c.attribute; };
    }
But that doesn't seem to fix it. Any help?

Xarn
Jun 26, 2015
Yeah, you are gonna have to provide more code to show what you are trying to do, and what the error is.

nielsm
Jun 1, 2009



Your operator== should generally be const, and take a const reference to the other object as parameter. But definitely provide some more specifics and more error messages.

Kuule hain nussivan
Nov 27, 2008

Xarn posted:

Yeah, you are gonna have to provide more code to show what you are trying to do, and what the error is.
Just let me know what you need and I'll try and post it. I'm still very new to C++ so I don't really have a good idea of what's relevant to the issue.

Qwertycoatl
Dec 31, 2008

Kuule hain nussivan posted:

Just let me know what you need and I'll try and post it. I'm still very new to C++ so I don't really have a good idea of what's relevant to the issue.

1) The code
2) The error message. If there are a zillion error messages, the first is the most relevant.

Dren
Jan 5, 2001

Pillbug
edit: nevermind

Dren fucked around with this message at 17:47 on Apr 19, 2019

Kuule hain nussivan
Nov 27, 2008

I think this is all the relevant stuff from .hh file.

code:
class Datastructures {
public:
    Datastructures();

    ~Datastructures();

private:
    struct Fiber;

    template<typename T>
    struct PointerHash {
        std::size_t operator()(T* pointer) const {
            auto addr = reinterpret_cast<uintptr_t>(pointer);
            //#if SIZE_MAX < UINTPTR_MAX
            //addr %= SIZE_MAX;
            //#endif
            return addr;
        }
    };

    struct XPoint {
        Coord coord = NO_COORD;
        std::unordered_set<Fiber*, PointerHash<typename std::remove_pointer<Fiber*>::type>> fibers;
    };

    struct Fiber {
        XPoint* from = nullptr;
        XPoint* to = nullptr;
        Cost cost = NO_COST;

        bool const operator==(const Fiber c) { return from == c.from && to == c.to; };
    };

    struct FiberHash
    {
        std::size_t operator()(Fiber fiber) const
        {
            auto hasher = std::hash<int>();
            auto xhash = hasher(fiber.from->coord.x) + hasher(fiber.to->coord.x);
            auto yhash = hasher(fiber.from->coord.y) + hasher(fiber.to->coord.y);
            // Combine hash values (magic!)
            return xhash ^ (yhash + 0x9e3779b9 + (xhash << 6) + (xhash >> 2));
        }
    };

    std::unordered_set<Fiber, FiberHash> fibers;
};
It's part of a pretty basic graph structure. XPoints are nodes, Fibers are edges. Whenever I try to add or erase a Fiber from fibers in my code, like below...

code:
bool Datastructures::add_fibre(XPoint xpoint1, XPoint xpoint2, Cost cost) {
    fibers.insert(Fiber{&fromXPoint->second, &toXPoint->second, cost});
    return true;
}
I get a bunch of errors, and I think this is the relevant one.

code:
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/stl_function.h: In instantiation of 'constexpr bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Datastructures::Fiber]':
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable_policy.h:1433:46:   required from 'static bool std::__detail::_Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, true>::_S_equals(const _Equal&, const _ExtractKey&, const _Key&, _HashCodeType, std::__detail::_Hash_node<_Value, true>*) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _HashCodeType = long unsigned int]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable_policy.h:1814:37:   required from 'bool std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::_M_equals(const _Key&, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type*) const [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code = long unsigned int; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type = std::__detail::_Hash_node<Datastructures::Fiber, true>]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:1551:4:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base* std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_find_before_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const key_type&, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code) const [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base = std::__detail::_Hash_node_base; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code = long unsigned int]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:1910:50:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_erase(std::true_type, const key_type&) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::true_type = std::integral_constant<bool, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:759:24:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::erase(const key_type&) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/unordered_set.h:544:30:   required from 'std::unordered_set<_Value, _Hash, _Pred, _Alloc>::size_type std::unordered_set<_Value, _Hash, _Pred, _Alloc>::erase(const key_type&) [with _Value = Datastructures::Fiber; _Hash = Datastructures::FiberHash; _Pred = std::equal_to<Datastructures::Fiber>; _Alloc = std::allocator<Datastructures::Fiber>; std::unordered_set<_Value, _Hash, _Pred, _Alloc>::size_type = long unsigned int; std::unordered_set<_Value, _Hash, _Pred, _Alloc>::key_type = Datastructures::Fiber]'
/cygdrive/c/Users/Sami Harju/Desktop/TiRaKa2018/prg2/datastructures.cc:541:34:   required from here
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/stl_function.h:356:20: error: no match for 'operator==' (operand types are 'const Datastructures::Fiber' and 'const Datastructures::Fiber')
       { return __x == __y; }
Now that I think about it, shouldn't the set only require the FiberHash-function?

Jose Valasquez
Apr 8, 2005

Kuule hain nussivan posted:

I think this is all the relevant stuff from .hh file.

code:
class Datastructures {
public:
    Datastructures();

    ~Datastructures();

private:
    struct Fiber;

    template<typename T>
    struct PointerHash {
        std::size_t operator()(T* pointer) const {
            auto addr = reinterpret_cast<uintptr_t>(pointer);
            //#if SIZE_MAX < UINTPTR_MAX
            //addr %= SIZE_MAX;
            //#endif
            return addr;
        }
    };

    struct XPoint {
        Coord coord = NO_COORD;
        std::unordered_set<Fiber*, PointerHash<typename std::remove_pointer<Fiber*>::type>> fibers;
    };

    struct Fiber {
        XPoint* from = nullptr;
        XPoint* to = nullptr;
        Cost cost = NO_COST;

        bool const operator==(const Fiber c) { return from == c.from && to == c.to; };
    };

    struct FiberHash
    {
        std::size_t operator()(Fiber fiber) const
        {
            auto hasher = std::hash<int>();
            auto xhash = hasher(fiber.from->coord.x) + hasher(fiber.to->coord.x);
            auto yhash = hasher(fiber.from->coord.y) + hasher(fiber.to->coord.y);
            // Combine hash values (magic!)
            return xhash ^ (yhash + 0x9e3779b9 + (xhash << 6) + (xhash >> 2));
        }
    };

    std::unordered_set<Fiber, FiberHash> fibers;
};
It's part of a pretty basic graph structure. XPoints are nodes, Fibers are edges. Whenever I try to add or erase a Fiber from fibers in my code, like below...

code:
bool Datastructures::add_fibre(XPoint xpoint1, XPoint xpoint2, Cost cost) {
    fibers.insert(Fiber{&fromXPoint->second, &toXPoint->second, cost});
    return true;
}
I get a bunch of errors, and I think this is the relevant one.

code:
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/stl_function.h: In instantiation of 'constexpr bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Datastructures::Fiber]':
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable_policy.h:1433:46:   required from 'static bool std::__detail::_Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, true>::_S_equals(const _Equal&, const _ExtractKey&, const _Key&, _HashCodeType, std::__detail::_Hash_node<_Value, true>*) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _HashCodeType = long unsigned int]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable_policy.h:1814:37:   required from 'bool std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::_M_equals(const _Key&, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code, std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type*) const [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__hash_code = long unsigned int; std::__detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, _Hash, _Traits>::__node_type = std::__detail::_Hash_node<Datastructures::Fiber, true>]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:1551:4:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base* std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_find_before_node(std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type, const key_type&, std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code) const [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_base = std::__detail::_Hash_node_base; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::__hash_code = long unsigned int]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:1910:50:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_M_erase(std::true_type, const key_type&) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::true_type = std::integral_constant<bool, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/hashtable.h:759:24:   required from 'std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::erase(const key_type&) [with _Key = Datastructures::Fiber; _Value = Datastructures::Fiber; _Alloc = std::allocator<Datastructures::Fiber>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Datastructures::Fiber>; _H1 = Datastructures::FiberHash; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, true>; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::size_type = long unsigned int; std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::key_type = Datastructures::Fiber]'
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/unordered_set.h:544:30:   required from 'std::unordered_set<_Value, _Hash, _Pred, _Alloc>::size_type std::unordered_set<_Value, _Hash, _Pred, _Alloc>::erase(const key_type&) [with _Value = Datastructures::Fiber; _Hash = Datastructures::FiberHash; _Pred = std::equal_to<Datastructures::Fiber>; _Alloc = std::allocator<Datastructures::Fiber>; std::unordered_set<_Value, _Hash, _Pred, _Alloc>::size_type = long unsigned int; std::unordered_set<_Value, _Hash, _Pred, _Alloc>::key_type = Datastructures::Fiber]'
/cygdrive/c/Users/Sami Harju/Desktop/TiRaKa2018/prg2/datastructures.cc:541:34:   required from here
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/stl_function.h:356:20: error: no match for 'operator==' (operand types are 'const Datastructures::Fiber' and 'const Datastructures::Fiber')
       { return __x == __y; }
Now that I think about it, shouldn't the set only require the FiberHash-function?

I think it is because your == operator isn't const so it isn't finding it

From the error message:

quote:

In instantiation of 'constexpr bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const

Jose Valasquez fucked around with this message at 18:15 on Apr 19, 2019

Dren
Jan 5, 2001

Pillbug
try this:
code:
class Datastructures {
public:
    Datastructures();

    ~Datastructures();

private:
    struct Fiber;

    template<typename T>
    struct PointerHash {
        std::size_t operator()(T* pointer) const {
            auto addr = reinterpret_cast<uintptr_t>(pointer);
            //#if SIZE_MAX < UINTPTR_MAX
            //addr %= SIZE_MAX;
            //#endif
            return addr;
        }
    };

    struct XPoint {
        Coord coord = NO_COORD;
        std::unordered_set<Fiber*, PointerHash<typename std::remove_pointer<Fiber*>::type>> fibers;
    };

    struct Fiber {
        XPoint* from = nullptr;
        XPoint* to = nullptr;
        Cost cost = NO_COST;

        friend bool operator==(const Fiber& first, const Fiber& second) { return first.from == second.from && first.to == second.to; };
    };

    struct FiberHash
    {
        std::size_t operator()(Fiber fiber) const
        {
            auto hasher = std::hash<int>();
            auto xhash = hasher(fiber.from->coord.x) + hasher(fiber.to->coord.x);
            auto yhash = hasher(fiber.from->coord.y) + hasher(fiber.to->coord.y);
            // Combine hash values (magic!)
            return xhash ^ (yhash + 0x9e3779b9 + (xhash << 6) + (xhash >> 2));
        }
    };

    std::unordered_set<Fiber, FiberHash> fibers;
};

Kuule hain nussivan
Nov 27, 2008

Dren posted:

try this:
code:
class Datastructures {
public:
    Datastructures();

    ~Datastructures();

private:
    struct Fiber;

    template<typename T>
    struct PointerHash {
        std::size_t operator()(T* pointer) const {
            auto addr = reinterpret_cast<uintptr_t>(pointer);
            //#if SIZE_MAX < UINTPTR_MAX
            //addr %= SIZE_MAX;
            //#endif
            return addr;
        }
    };

    struct XPoint {
        Coord coord = NO_COORD;
        std::unordered_set<Fiber*, PointerHash<typename std::remove_pointer<Fiber*>::type>> fibers;
    };

    struct Fiber {
        XPoint* from = nullptr;
        XPoint* to = nullptr;
        Cost cost = NO_COST;

        friend bool operator==(const Fiber& first, const Fiber& second) { return first.from == second.from && first.to == second.to; };
    };

    struct FiberHash
    {
        std::size_t operator()(Fiber fiber) const
        {
            auto hasher = std::hash<int>();
            auto xhash = hasher(fiber.from->coord.x) + hasher(fiber.to->coord.x);
            auto yhash = hasher(fiber.from->coord.y) + hasher(fiber.to->coord.y);
            // Combine hash values (magic!)
            return xhash ^ (yhash + 0x9e3779b9 + (xhash << 6) + (xhash >> 2));
        }
    };

    std::unordered_set<Fiber, FiberHash> fibers;
};

This did it! Thank you very much!

What is the magic behind the 'friend' keyword? Without it, my IDE complains that I'm giving the operator 3 parameters, which I've understood is caused by an implied this-parameter.

qsvui
Aug 23, 2003
some crazy thing
Using friend is the only way to declare non-member functions inside a class. In this case, friend has nothing to do with access.

Dren
Jan 5, 2001

Pillbug
I declare it with the friend keyword because of core guidelines rule C.161: Use nonmember functions for symmetric operators

http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c161-use-nonmember-functions-for-symmetric-operators

I wasn't sure the syntax for declaring a free function in the outer class's namespace or if it's even allowed, so I declared it friend inside the struct.

You had another problem which was that the argument to operator== wasn't const reference. I think that was the only thing stopping you from compiling.

Lime
Jul 20, 2004

Kuule hain nussivan posted:

code:
    struct Fiber {
        XPoint* from = nullptr;
        XPoint* to = nullptr;
        Cost cost = NO_COST;

        bool const operator==(const Fiber c) { return from == c.from && to == c.to; };
    };

Just want to point out one thing: the syntax for const member functions has the const after the argument list. As written here, it is still not a const member function, it merely returns a const bool. You need to write:

code:
bool operator==(const Fiber c) const { return from == c.from && to == c.to; };

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
Is it possible to create a specialized version of this function to use when OutChannels is 1? I'm not sure it is even possible.. I have no idea what the syntax would be if it were possible.

code:
template< typename T, int InChannels, int OutChannels >
void SetAudioData( AudioData< T, OutChannels >& out, const AudioData< T, InChannels >& in )
{
	// blah
}
e: I think maybe this answers my question https://stackoverflow.com/questions/12683165/partial-specialization-of-templates-with-integer-parameters

baby puzzle fucked around with this message at 16:35 on Apr 22, 2019

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Just overload it. Function template specialization partial ordering should pick the more specialized candidate. You can static_assert in the other candidate if you're worried about it.

Rahu
Feb 14, 2009


let me just check my figures real quick here
Grimey Drawer
Not strictly a c++ question here but a question about c++ projects with visual studio, I didn't see a better thread to post this in.

I recently moved a project I am working on from VS 2015 to 2017. When I brought it into 2017 I re-targeted it to use the new v141 toolset.

Despite this, my project still has "(Visual Studio 2015)" appended to it's name in the solution explorer. As far as I can tell this project is actually building with the new 2017 compiler, I'm just unsure of why it is still marked as a 2015 project. The project properties windows shows the toolset as v141.

This isn't actually causing me any problems and everything is working how I expect, I'm just not sure what the (Visual Studio 2015) designation means or if it is having any meaningful impact on my project. Anyone know what is up with this?

Nehacoo
Sep 9, 2011

Rahu posted:

Not strictly a c++ question here but a question about c++ projects with visual studio, I didn't see a better thread to post this in.

I recently moved a project I am working on from VS 2015 to 2017. When I brought it into 2017 I re-targeted it to use the new v141 toolset.

Despite this, my project still has "(Visual Studio 2015)" appended to it's name in the solution explorer. As far as I can tell this project is actually building with the new 2017 compiler, I'm just unsure of why it is still marked as a 2015 project. The project properties windows shows the toolset as v141.

This isn't actually causing me any problems and everything is working how I expect, I'm just not sure what the (Visual Studio 2015) designation means or if it is having any meaningful impact on my project. Anyone know what is up with this?

Did you change toolset for all build configurations? I think it will still show that "(Visual Studio 2015)" if even one of the build configurations uses the old toolset.

Rahu
Feb 14, 2009


let me just check my figures real quick here
Grimey Drawer
Ah, that was sort of it.

I had changed all of my build configurations to use v141, but I was referencing a .props file that still was setting v140 as the default toolset. Even though every build configuration was overriding that to v141, it still made the (Visual Studio 2015) come up.

Thanks :)

Illusive Fuck Man
Jul 5, 2004
RIP John McCain feel better xoxo 💋 🙏
Taco Defender
Any ASIO experts know a prettier way to write AsyncReadOneByte()? I feel like the effort involved in order to just adapt a completion handler to accept/return stuff is pretty annoying. Is there a way to replace the struct with like boost::asio::bind_executor() and a lambda?

I copy pasted the documentation's about executor_type / get_executor(). I don't understand why it is 'essential for correctness to preserve the executor of the user-supplied completion handler.' Is there a good doc or video about this?

code:
template <typename AsyncReadStream, typename CompletionToken>
typename boost::asio::async_result<CompletionToken,
                                   void(boost::system::error_code,
                                        unsigned char)>::return_type
AsyncReadOneByte(AsyncReadStream &&stream, CompletionToken &&token) {
  using completion_handler_type = typename boost::asio::async_completion<
      CompletionToken,
      void(boost::system::error_code, unsigned char)>::completion_handler_type;

  struct Op {
    AsyncReadStream &stream_;
    completion_handler_type handler_;
    std::unique_ptr<unsigned char> data_;

    // It is essential to the correctness of our composed operation that we
    // preserve the executor of the user-supplied completion handler. With a
    // hand-crafted function object we can do this by defining a nested type
    // executor_type and member function get_executor. These obtain the
    // completion handler's associated executor, and default to the I/O
    // executor - in this case the executor of the socket - if the completion
    // handler does not have its own.
    using executor_type = boost::asio::associated_executor_t<
        completion_handler_type,
        decltype(std::declval<AsyncReadStream>().get_executor())>;

    executor_type get_executor() const noexcept {
      return boost::asio::get_associated_executor(handler_,
                                                  stream_.get_executor());
    }

    void operator()(boost::system::error_code ec, std::size_t) {
      unsigned char result = *data_;
      data_.reset();
      handler_(ec, result);
    }
  };

  boost::asio::async_completion<CompletionToken,
                                void(boost::system::error_code, unsigned char)>
      completion(token);

  auto data = std::make_unique<unsigned char>();
  std::size_t data_size = 1;
  auto buffer = boost::asio::buffer(data.get(), data_size);
  boost::asio::async_read(
      stream, std::move(buffer),
      Op{stream, std::move(completion.completion_handler), std::move(data)});
  return completion.result.get();
}

Illusive Fuck Man
Jul 5, 2004
RIP John McCain feel better xoxo 💋 🙏
Taco Defender
Looks like boost 1.70 added a slightly nicer way to set up composed operations. It's still not pretty, but less noisy than before, and I think it does the 'correct' thing w/r/t executors. Extremely c++14+ only though.


code:
template <typename AsyncReadStream, typename CompletionToken>
auto AsyncReadOneByte(AsyncReadStream &&stream, CompletionToken &&token) {
  auto data = std::make_unique<unsigned char>();
  enum { kStarting, kReading };
  return boost::asio::async_compose<
      CompletionToken, void(boost::system::error_code, unsigned char)>(
      [&stream, state = kStarting,
       data = std::move(data) ](auto &self, boost::system::error_code ec = {},
                                std::size_t = 0) mutable {
        switch (state) {
        case kStarting:
          state = kReading;
          boost::asio::async_read(stream, boost::asio::buffer(data.get(), 1),
                                  std::move(self));
          return;
        case kReading:
          self.complete(ec, *data);
        }
      },
      token, stream);
}

MrMoo
Sep 14, 2000

What's the goal beyond boost::asio::async_read(s, boost::asio::buffer(data, 1u), handler);?

I'm getting owned everyday trying to get HTTPS health checks from AWS ELB working with ASIO and Beast. The docs are rear end for both Boost and AWS.

1) Health check is failing and killing my ECS instances. What precisely is the failure is actually not noted. It may be a non-200 code or a failure to connect and read within a time limit. I can tell from logs when my app should be reporting success though. It can take a while to startup, and can get killed before it is in a ready state.
2) In pretty much default setup I run out of memory due to the server-side caching of OpenSSL's session cache with a default limit of 20,000 sessions that apparently means many GBs.
3) TLS session tickets are enabled by default and AWS doesn't appear to care.
4) AWS has a requirement on ciphers and SSL/TLS levels, you can configure on the frontend but is locked on the backend.
5) Whatever you setup in OpenSSL appears to be completely ignored by the openssl CLI but can be picked up in other tools as long as they don't crash out completely, i.e. sslscan.
6) ASIO SSL Context options are retarded. Apparently compression is disabled by default and there is an option to disable compression. However AWS ELB appears to want compression as SSL handshake raises an error if you explicitly disable compression.
7) There is a default_workarounds set of options for like SSLv1/v2 days that everyone still uses in examples and code. Skip that poo poo already, no one uses MSIE 3 or whatever any more.
8) You can set the SSL Context to be tlsv12_server yet still connect with TLSv1.0 or v1.1, this is messed up.
9) RHEL OpenSSL disables all elliptical ciphers by default or something like that and those ciphers with caching disabled appear to raise timeouts with AWS ELB. Now I jump to that conclusion by comparing the output of sslscan from the C++ servers to the Go ones, however when using openssl CLI it will go ahead and use an ECC cipher without issue. Nice.
10) AWS ELB has configuration for health check intervals and it pretty much has no meaning as you will receive 6 connections per second from all over the world no matter what you set. How 6 requests/second can overload OpenSSL is beyond my understanding.

I'm comparing to a server written in Go using BoringSSL, and another C++ server using bespoke (probably derived from the examples) HTTPS server. Both of those have no disconnects or errors. The latter does not implement keepalives at all and just closes after each request. Possibly irrelevant but the Go server has 50/50% TCP RSTs driven by the client and server, suggesting a keepalive period is too short, the C++ server is somehow 100% driven by the client which makes no sense at all if it closing after a response. It is possible they messed up with SSL shutdown and just close out the socket, apparently the session cache is only written on a clean SSL shutdown. When I have session caching enabled I see 100% TCP RSTs generated by my C++ server app, most likely because the idle timeout is too short. AWS ELB is apparently hard coded to 60s.

I have one thread that is shared between ASIO TCP server (with no connections, lol) and Beast/HTTPS. the other C++ is one thread dedicated to HTTPS serving. If the health check errors are due to timeouts this should be a complete apples-to-apples comparison as the only code here should be async_accept and async_handshake?

I need to raise up with AWS support soon, I'm waiting on one last test with a forced ECC cipher and a manually set cache size limit and timeout.

MrMoo fucked around with this message at 05:12 on May 2, 2019

Illusive Fuck Man
Jul 5, 2004
RIP John McCain feel better xoxo 💋 🙏
Taco Defender

MrMoo posted:

What's the goal beyond boost::asio::async_read(s, boost::asio::buffer(data, 1u), handler);?

Pretty much just trying to make it read nicer and make it so the caller doesn't have to manage the buffer lifetime. My next step is to compose these little operations into more complex stateful ones implementing a protocol.

MrMoo
Sep 14, 2000

The forced ECC build is pending verification because ECS load balancers keep pointing to the wrong target group. So disabling that in another build and test again. I'll definitely laugh if it turns out AWS ELB requires default_workarounds to be enabled and everything is a red herring.

drainpipe
May 17, 2004

AAHHHHHHH!!!!
I'd like to learn modern C++. Is there a good intro book for that? It seems like Stroustrup's book is more of a reference and Koenig/Moo is almost 20 years old. I had done some C++ over a decade ago in high school, but kinda stopped there. For reference, I'm an adequate programmer. I'm comfortable with C and basic object-oriented concepts.

Star War Sex Parrot
Oct 2, 2003

Probably Meyers Effective Modern C++. I dont think its been updated for C++17, but thats easy enough to sort out.

This isnt bad either, for a high level overview:
https://ds9a.nl/articles/posts/cpp-intro/

qsvui
Aug 23, 2003
some crazy thing
A Tour of C++ has been updated for C++17, you could try checking that out. It is not an intro to programming book and is more of an overview of C++. The target audience seems to be experienced developers who've taken a break from C++ and is now trying their hand at it again.

(Note that I've only read the 1st edition of this book so I don't know how adequately it covers the new stuff.)

MrMoo
Sep 14, 2000

MrMoo posted:

The forced ECC build is pending verification because ECS load balancers keep pointing to the wrong target group. So disabling that in another build and test again. I'll definitely laugh if it turns out AWS ELB requires default_workarounds to be enabled and everything is a red herring.

Almost everything a red herring, finger pointing to IO context concurrency hint value of 1 being utterly broken. The thread stalls on a particular 2-cpu EC2 node and nowhere else. Such fun waiting 30-mins to get a Docker image build and another 30 for it to be deployed for a runtime of 2 minutes to flag success or failure.

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
I tend to do this a lot when I want a thread-safe data structure that I know will be used in multiple threads:

code:
	std::vector< std::shared_ptr< Blah > > m_blahs;
	std::mutex m_blahsMutex;
and then I make sure to lock m_BlahsMutex anywhere that I might be using m_Blahs.

code:
{
	std::lock_guard< std::mutex > locker( m_blahsMutex );
	m_blahs.push_back( whatever );
}
This is obviously error prone, so what's the right way to do this?

e: I guess what would be great is some kind of either runtime or compile time thing that alerts me to non-protected uses of the vector, but I know this is c++ and not rust so I don't know if that exists.

baby puzzle fucked around with this message at 21:32 on May 7, 2019

Volguus
Mar 3, 2009
That is the right thing to do. You protect it whenever you modify or access/loop the vector. Better: lock free structures. That is, structures that are thread safe and they accomplish that without the use of a mutex or lock. One example is https://www.boost.org/doc/libs/1_63_0/doc/html/lockfree.html . There are others as well.

c0burn
Sep 2, 2003

The KKKing
Hello friends

Because I'm a masochist, I'd like to program a DOS game, directly on the VGA hardware, either mode 13 or mode-X
I know C and C++ very well, but I've only ever learnt their standard libraries and and modern libraries like SDL and SFML and never did things on the "metal" like bios interrupts, dos.h and mem.h from the cool old days of DOS programming
I have access to a real DOS PC with 6.22 and Windows 3.1, also DOSBox, various Borland and MS compilers from the late 80's and early 90's - what's the best original compiler?
I looked into DJGPP but I probably want real mode not protected mode?

Can anyone recommend some good books from back in the day? Covering things like the DOS API/Interrupts, VGA hardware, Borland/MS C, maybe some Turbo Assembler/Microsoft Assembler?
I feel like things like the oft recommended Mike Abrash books are for people who already know the basics of DOS and VGA programming and I'd need to start simpler

Thank you

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

c0burn posted:

Hello friends

Because I'm a masochist, I'd like to program a DOS game, directly on the VGA hardware, either mode 13 or mode-X
I know C and C++ very well, but I've only ever learnt their standard libraries and and modern libraries like SDL and SFML and never did things on the "metal" like bios interrupts, dos.h and mem.h from the cool old days of DOS programming
I have access to a real DOS PC with 6.22 and Windows 3.1, also DOSBox, various Borland and MS compilers from the late 80's and early 90's - what's the best original compiler?
I looked into DJGPP but I probably want real mode not protected mode?

Can anyone recommend some good books from back in the day? Covering things like the DOS API/Interrupts, VGA hardware, Borland/MS C, maybe some Turbo Assembler/Microsoft Assembler?
I feel like things like the oft recommended Mike Abrash books are for people who already know the basics of DOS and VGA programming and I'd need to start simpler

Thank you
Are you interested in learning how to do things on the metal, or in learning how legacy systems used to work? Those are very different these days; all the interfaces you're talking to are either completely dead, or emulated by hardware that works very differently internally.

c0burn
Sep 2, 2003

The KKKing

Ralith posted:

Are you interested in learning how to do things on the metal, or in learning how legacy systems used to work? Those are very different these days; all the interfaces you're talking to are either completely dead, or emulated by hardware that works very differently internally.

I'd like it to work on a real DOS PC and DOSbox
From some googling, you call some BIOS interrupts, set some registers and poke at the VGA memory directly - am I using the wrong terminology when I say "metal"?

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.

Volguus posted:

That is the right thing to do. You protect it whenever you modify or access/loop the vector. Better: lock free structures. That is, structures that are thread safe and they accomplish that without the use of a mutex or lock. One example is https://www.boost.org/doc/libs/1_63_0/doc/html/lockfree.html . There are others as well.

but.. that relies on me not being an idiot.. Actually sometimes I name things like myVector_protected, or something obnoxious when I know it is used in different threads and I need the constant reminder.

I use lock-free queues for sending messages between threads, and I think they are pretty cool.

But its arrays/vectors/maps where I tend to get mixed up...

csammis
Aug 26, 2003

Mental Institution

c0burn posted:

I'd like it to work on a real DOS PC and DOSbox
From some googling, you call some BIOS interrupts, set some registers and poke at the VGA memory directly - am I using the wrong terminology when I say "metal"?

Its the right terminology but the wrong era. What Ralith is saying is that the low-level programming skills you learn programming a DOS-era computer at the level you described wont translate to programming anything modern at the equivalent level. The at the metal level youre talking about simply doesnt exist for something like a Cortex-M series microcontroller, or in the case of modern PCs its emulated for backwards compatibility.

Thats not to say it wouldnt be fun to do! Just be aware that it might not be helpful in TYOOL 2019 :)

c0burn
Sep 2, 2003

The KKKing
Oh I see. Yeah I get that it won't translate to modern hardware. This is just for fun!

Adbot
ADBOT LOVES YOU

Volguus
Mar 3, 2009

baby puzzle posted:

but.. that relies on me not being an idiot.. Actually sometimes I name things like myVector_protected, or something obnoxious when I know it is used in different threads and I need the constant reminder.

I use lock-free queues for sending messages between threads, and I think they are pretty cool.

But its arrays/vectors/maps where I tend to get mixed up...

Well, encapsulate the vector in your own class where you do protect stuff. You would have to provide a different way to iterate over elements, you cannot just expose the begin/end, or any other bit more convoluted operation, but other than that, you can do it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply