Предупреждение C4316: объект, выделенный в куче, может быть не выровнен 16

Важная информация:

  • Разработка ОС: Windows 8.1 64 бит
  • Целевая ОС: Windows 8.1 64 бит
  • IDE: Visual Studio 2013 Professional
  • Язык: C++

Эта проблема:

При компиляции проекта статической библиотеки через IDE я получаю следующее предупреждение:

warning C4316: ... : object allocated on the heap may not be aligned 16

Я мог бы просто проигнорировать это предупреждение... но я предполагаю, что оно есть по какой-то причине и хотел бы хотя бы понять, что это значит и какие последствия это может иметь в будущем.

Я считаю, что эта строка кода связана с проблемой, которая вызывается в моем классе оболочки Windows Win32:

m_direct3D = new Direct3D(this);

m_direct3D - указатель на мой класс-оболочку Direct3D.

Вот заголовочный файл для обертки (я допускаю, что он нуждается в обрезке):

#pragma once

// Windows
#include <d3d11.h>
#include <DirectXMath.h>

// Standard
#include <stdint.h>
#include <vector>

// JGlib
#include "Window.h"

namespace JGlib
{
    namespace Graphics
    {
        class Direct3D
        {
        public:
            // Construtor and destructor
            Direct3D(const JGlib::Graphics::Window* window);
            ~Direct3D();

            // Public methods
            void Initialise();
            void BeginDraw();
            void Draw();
            void EndDraw();

        private:
            // Private methods

            // Private member variables
            const Window*               m_window;
            ID3D11Device*               m_device;
            IDXGIAdapter*               m_adapter;
            DXGI_ADAPTER_DESC           m_adapterDescription;
            uint32_t                    m_videoCardMemory;
            IDXGIFactory*               m_factory;
            IDXGIOutput*                m_monitor;
            DXGI_MODE_DESC*             m_displayModes;
            uint32_t                    m_numberOfModes;    
            DXGI_RATIONAL               m_refreshRate;
            DXGI_SWAP_CHAIN_DESC        m_swapChainDescription;
            D3D_FEATURE_LEVEL           m_featureLevel;
            ID3D11DeviceContext*        m_deviceContext;
            IDXGISwapChain*             m_swapChain;
            ID3D11Texture2D*            m_backBuffer;
            ID3D11RenderTargetView*     m_renderTargetView;
            ID3D11Texture2D*            m_depthStencilBuffer;
            D3D11_TEXTURE2D_DESC        m_depthBufferDescription;
            D3D11_DEPTH_STENCIL_DESC    m_depthStencilDescription;
            ID3D11DepthStencilState*    m_depthStencilState;
            ID3D11DepthStencilView*     m_depthStencilView;
            D3D11_RASTERIZER_DESC       m_rasterDescription;
            D3D11_VIEWPORT              m_viewport; 
            float                       m_fieldOfView;
            float                       m_screenAspectRatio;
            ID3D11RasterizerState*      m_rasterState;
            DirectX::XMMATRIX           m_projectionMatrix;
            DirectX::XMMATRIX           m_worldMatrix;
            DirectX::XMMATRIX           m_orthographicMatrix;
            float                       m_screenDepth;
            float                       m_screenNear;
        };
    }
}

Я попытался погуглить вопрос, но нашел мало информации. Информацию, которую я нашел, я не понял.

В заключение я прошу следующее:

  1. Что означает C4316?
  2. Что вызывает это в моем коде?
  3. Какие последствия это может иметь в будущем, если я проигнорирую это?
  4. Как мне "исправить" проблему, из-за которой появляется это предупреждение?

Дополнительная информация:

Когда я изменил диспетчер конфигурации Visual Studio для компиляции для x64, эта проблема не возникала.

4 ответа

Решение

Что означает C4316?

C4316- это код ошибки. Это уникальный идентификатор, который облегчает поиск документации.

Что вызывает это в моем коде?

Использование DirectX::XMMATRIX учебный класс. Экземпляры этого класса должны быть выровнены по 16-байтовым границам. Компилятор гарантирует, что всякий раз, когда вы создаете JGLib::Graphics::Direct3D экземпляр в стеке или в глобальной области видимости, он будет правильно выровнен, но если вы динамически выделяете экземпляр в куче, компилятор не может гарантировать, что объект будет правильно выровнен, потому что malloc() а друзья обычно гарантируют только 8-байтовое выравнивание.

Какие последствия это может иметь в будущем, если я проигнорирую это?

Ваш код может дать сбой при доступе к этим экземплярам матрицы из-за инструкций SSE, работающих с смещенными данными.

Как мне "исправить" проблему, из-за которой появляется это предупреждение?

Как видно из документации, вам нужно переопределить класс operator new а также operator delete чтобы гарантировать 16-байтовое выравнивание. Ты можешь использовать _aligned_malloc() а также _aligned_free() выделить и освободить память, выровненную по большим выравниваниям.

Вам нужно переопределить операторы new и delete, например:

__declspec(align(16)) class MyClass
{
    public:
    DirectX::XMMATRIX           m_projectionMatrix;

    virtual ~MyClass()
    {
    }

    void* operator new(size_t i)
    {
        return _mm_malloc(i,16);
    }

    void operator delete(void* p)
    {
        _mm_free(p);
    }
};

Если вы посмотрите на предварительно обработанный код, вы, вероятно, найдете что-то вроде этого __declspec(align(16)) там, запрашивая выравнивание на 16 байтов в то время как new может не выравниваться при этом ограничении. Согласно http://msdn.microsoft.com/en-us/library/vstudio/dn448573.aspx вы можете исправить это, Override operator new and operator delete for over-aligned types so that they use the aligned allocation routines—for example, _aligned_malloc and _aligned_free.

DirectX::XMMATRIX содержит данные SSE (и отмечен __declspec(align(16)) из-за этого) и, следовательно, должны быть выровнены по границе 16B, в противном случае доступ к ним приведет к нарушению доступа.

Предупреждение говорит о том, что оператор не вернул гарантийную память. New выровнен на 16B.

Можете ли вы создать объект как глобальную или локальную переменную? Таким образом, компилятор может обеспечить выравнивание. Если вы не можете, вы можете предоставить перегруженный new а также delete для тебя Direct3D класс реализован с использованием _aligned_malloc и _aligned_free.

Другие вопросы по тегам