'why does memcpy copy only the first element of std::vector?

I'm trying to copy vector of DirectX::XMMATRIX elements into a Direct3D vertex shader constant buffer, but it only copies the first element (which is 4x4 float matrix, which is 64 bytes), resulting in an exception (it expects 3 elements, 192 bytes total, which vector has)

Here's a sample code:

template<typename C>
void Update(const std::vector<C>* cbuf)
{
    D3D11_MAPPED_SUBRESOURCE msr = {};
    GetContext()->Map(m_pConstBuffer.Get(), 0u, D3D11_MAP_WRITE_DISCARD, 0u, &msr);
    memcpy(msr.pData, &cbuf[0], sizeof(C) * cbuf->size());
    GetContext()->Unmap(m_pConstBuffer.Get(), 0u);
}

I also tried memcpy(msr.pData, cbuf->data(), sizeof(C) * cbuf->size()), as well as specifically stating to copy 192 bytes - and yes - sizeof(C) * cbuf->size() results in 192 - but it still copies 64 bytes of the first element

So what's wrong? Isn't the vector contiguous?



Solution 1:[1]

The problem here I believe is that you are passing the std::vector as a pointer so &cbuf[0] isn't doing what you think it is doing.

You can also make it a little more generic:

template<typename T>
void Update(T const& cbuf)
{
    auto context = GetContext();
    auto cb = m_pConstBuffer.Get();
    D3D11_MAPPED_SUBRESOURCE msr = {};
    if (SUCCEEDED(context->Map(cb, 0u, D3D11_MAP_WRITE_DISCARD, 0u, &msr)))
    {
        memcpy(msr.pData,
            cbuf.data(),
            sizeof(typename T::value_type) * cbuf.size());
        context->Unmap(cb, 0u);
    }
}

You don't show the creation of the resource so if this doesn't work, try looking at that.

You may want to take a look at DirectX Tool Kit for DX11. There's a MapGuard class similar to what you are doing and the BufferHelpers.h header might give you some ideas as well.

Solution 2:[2]

The best practice would be to change the server status code - 307 (Temporary Redirect) or 308 (Permanent Redirect).

If the server replies with a redirect, the Client first uses the CheckRedirect function to determine whether the redirect should be followed. If permitted, a 301, 302, or 303 redirect causes subsequent requests to use HTTP method GET (or HEAD if the original request was HEAD), with no body. A 307 or 308 redirect preserves the original HTTP method and body, provided that the Request.GetBody function is defined. The NewRequest function automatically sets GetBody for common standard library body types.

Another super hacky way could be - changing the request in CheckRedirect function https://github.com/golang/go/blob/master/src/net/http/client.go#L78 https://github.com/golang/go/blob/master/src/net/http/client.go#L691

 // example hack
 func FollowRedirectForPost(data io.Reader) {
    client := &http.Client{
        CheckRedirect: func(req *Request, via []*Request) error {
            // check status code etc.
            req.Method = http.MethodPost
            req.Body = data
        }
    }
    
    req, _ := http.NewRequest(http.MethodPost, "example.com/test", data)

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    client.Do(req) // If server returns 302 Redirect so it means I need make the same request with the same body to
    // a different location. Just imagine i replaced "example.com/test" to "example.com/redirect_url"
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 shahin mahmud