-2

I'm reading a book "Multiplayer games. Development of network applications" by Joshua Glazer and Sanjay Madhav.

class SocketAddress
{
public:
  SocketAddress(const sockaddr& inSockAddr)
  {
    memcpy(&mSockAddr, &inSockAddr, sizeof(sockaddr));
  }
private:
  sockaddr mSockAddr;
}

I wonder why the author fills sockaddr structure using memcpy, not just mSockAddr = inSockAddr.

  • 3
    Only opinion based answer is possible. Perhaps the authors have a reach C background. Even in C, `mSockAddr = inSockAddr` would work. – 273K Oct 20 '22 at 16:29
  • Some people just prefer it, even when the type contains non-POD members. I had to defend a member-by-member deep copy once in code review. After explaining, they were just, "...I guess." – sweenish Oct 20 '22 at 17:07

1 Answers1

1

This code is incorrect since sockaddr's size is arbitrary, and only meant to be used as a pointer to cast to a more derived type like sockaddr_in or sockaddr_in6.

You need the memcpy because you may need to copy padding bits, which mSockAddr = inSockAddr doesn't do. You also don't know the size after the structure has been cast to const sockaddr&.

A corrected version of the code would look like:

class SocketAddress
{
public:
  SocketAddress(const sockaddr_storage& inSockAddrStorage, std::size_t addrLen) : size(addrLen)
  {
    std::memcpy(&mSockAddr, &inSockAddrStorage, size);
  }
  SocketAddress(const sockaddr& inSockAddr, std::size_t addrLen) : size(addrLen)
  {
    std::memcpy(&mSockAddr, &inSockAddr, size);
  }
  SocketAddress(const SocketAddress& other) : size(other.size)
  {
    std::memcpy(&mSockAddr, &other.sockAddr, size);
  }

  // Add overloads for common socket types
  SocketAddress(const sockaddr_in& inSockAddrIn) : SocketAddress(reinterpret_cast<const sockaddr&>(inSockAddrIn), sizeof(sockaddr_in)) {}
  SocketAddress(const sockaddr_in6& inSockAddrIn6) : SocketAddress(reinterpret_cast<const sockaddr&>(inSockAddrIn6), sizeof(sockaddr_in6)) {}
  SocketAddress(const sockaddr_un& inSockAddrUn) : SocketAddress(reinterpret_cast<const sockaddr_un&>(inSockAddrUn), sizeof(sockaddr_un)) {}

  // operator= for this class will work
  SocketAddress& operator=(const SocketAddress& other) {
    size = other.size;
    std::memmove(&mSockAddr, &other.mSockAddr, size);
    return *this;
  }
private:
  sockaddr_storage mSockAddr;
  std::size_t size;
}
Artyer
  • 31,034
  • 3
  • 47
  • 75