Предупреждение C4316: объект, выделенный в куче, не может быть выровнен 16
Важная информация:
- ОС для разработки: Windows 8.1 64 бит
- Целевая ОС: Windows 8.1 64 бит
- IDE: Visual Studio 2013 Professional
- Язык: С++
Проблема:
Я получаю следующее предупреждение при компиляции моего проекта статической библиотеки через среду IDE:
warning C4316: ... : object allocated on the heap may not be aligned 16
Я мог просто проигнорировать это предупреждение... но я предполагаю это там по какой-то причине и хотел бы хотя бы понять, что это значит и какие последствия он может иметь в будущем.
Я считаю, что эта строка кода связана с проблемой, которая вызывается внутри моего класса оболочки 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;
};
}
}
Я попытался разобраться с проблемой, но нашел мало информации. Информация, которую я нашел, я не понимал.
В заключение я прошу следующее:
- Что означает C4316?
- Что вызывает его в моем коде?
- Какие последствия может иметь это в будущем, если я его игнорирую?
- Как мне исправить проблему, вызывающую это предупреждение?
Дополнительная информация:
Когда я сменил диспетчер конфигурации Visual Studio для компиляции для x64, эта проблема не возникает.
Ответы
Ответ 1
Что означает C4316?
C4316 - код ошибки. Это уникальный идентификатор, который упрощает поиск документации.
Что вызывает его в моем коде?
Использование класса DirectX::XMMATRIX
. Экземпляры этого класса должны быть выровнены по 16-байтовым границам. Компилятор гарантирует, что всякий раз, когда вы создаете экземпляр JGLib::Graphics::Direct3D
в стеке или в глобальной области действия, он будет правильно его выровнять, но если вы распределите экземпляр динамически в куче, компилятор не может гарантировать, что объект будет выровнен правильно, потому что malloc()
и друзья обычно поддерживают только 8-байтовое выравнивание.
Какие последствия могут иметь это в будущем, если я его игнорирую?
Ваш код может сбой при доступе к этим экземплярам матрицы из-за инструкций SSE, работающих с несогласованными данными.
Как мне исправить проблему, вызывающую это предупреждение?
Как следует из документации, вам необходимо переопределить класс operator new
и operator delete
, чтобы гарантировать выравнивание по 16 байт. Вы можете использовать _aligned_malloc()
и _aligned_free()
для выделения и освобождения памяти, совмещенной с большими выравниваниями.
Ответ 2
Вам необходимо переопределить новые и удалить операторы, например:
__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);
}
};
Ответ 3
Если вы посмотрите на предварительно обработанный код, вы, вероятно, найдете там что-то вроде этого __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.
Ответ 4
DirectX::XMMATRIX
содержит SSE-данные (и помечен как __declspec(align(16)
) из-за этого), и поэтому их необходимо выровнять по границе 16B, иначе инструкции, обращающиеся к нему, вызовут нарушение прав доступа.
Предупреждение сообщает вам, что гарантийная память, возвращаемая оператором new, не выровнена на 16B.
Можете ли вы создать объект как глобальную или локальную переменную? Таким образом, компилятор может обеспечить выравнивание. Если вы не можете, вы можете предоставить перегруженные new
и delete
для вашего класса Direct3D
, реализованного с помощью _ aligned_malloc и _ aligned_free.