慎用USES_CONVERSION

原文出处:http://www.cnblogs.com/carekee/articles/1935789.html

慎用USES_CONVERSION

USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。在ATL下使用要包含头文件#include "atlconv.h"

使用USES_CONVERSION一定要小心,它们从堆栈上分配内存,直到调用它的函数返回,该内存不会被释放。如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。

 

在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。

#include <atlconv.h>
void fn()
{
    while(true)
    {
        {
            USES_CONVERSION;
            DoSomething(A2W("SomeString"));
        }
    }
}

让我们来分析以上的转换宏

#define A2W(lpa) (\
   ((_lpa = lpa) == NULL) ? NULL : (\
      _convert = (lstrlenA(_lpa)+1),\
      ATLA2WHELPER((LPWSTR) alloca(_convert*2), _lpa, _convert)))

#define ATLA2WHELPER AtlA2WHelper

inline LPWSTR WINAPI AtlA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
{
   ATLASSERT(lpa != NULL);
   ATLASSERT(lpw != NULL);
   // verify that no illegal character present
   // since lpw was allocated based on the size of lpa
   // don't worry about the number of chars
   lpw[0] = '\0';
   MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
   return lpw;
}

关键的地方在 alloca  内存分配内存上。
#define alloca  _alloca

_alloca
Allocates memory on the stack.

Remarks
_alloca allocates size bytes from the program stack. The allocated space is automatically freed when the calling function

exits. Therefore, do not pass the pointer value returned by _alloca as an argument to free.

问题就在这里,分配的内存是在函数的栈中分配的。而VC编译器默认的栈内存空间是2M。当在一个函数中循环调用它时就会不断的分配栈中的内存。

以上问题的解决办法:
1、自己写字符转换函数,不要偷懒
Function that safely converts a 'WCHAR' String to 'LPSTR':
char* ConvertLPWSTRToLPSTR (LPWSTR lpwszStrIn)
{
  LPSTR pszOut = NULL;
  if (lpwszStrIn != NULL)
  {
 int nInputStrLen = wcslen (lpwszStrIn);

 // Double NULL Termination
 int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
 pszOut = new char [nOutputStrLen];

 if (pszOut)
 {
   memset (pszOut, 0x00, nOutputStrLen);
   WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
 }
  }
  return pszOut;
}
等等一个一个的实现。

2、把字符转换部分放到一个函数中处理。

void fn2()
{
    USES_CONVERSION;
    DoSomething(A2W("SomeString"));
}

void fn()
{
    while(true)
    {
        fn2();
    }
}

如果不知道这点问题,在使用后崩溃时很难查出崩溃原因的。


(pdal-env) D:\scau_lidar_data\output>3d-tiles-tools lasTo3dtiles -i C22.las -o h Usage: 3d-tiles-tools <command> [options] Commands: convert Convert between tilesets and tileset package formats. The input and output can be one of the following: - The path of a tileset JSON file - The path of a directory that contains a 'tileset.json' file - The path of a '.3tz' file - The path of a '.3dtiles' file The input can also be the path of a ZIP file that contains the tileset data. The tileset JSON file in this ZIP is determined by the 'inputTilesetJsonFileName', which is 'tileset.json' by default. glbToB3dm Repackage the input glb as a b3dm with a basic header. glbToI3dm Repackage the input glb as a i3dm with a basic header. b3dmToGlb Extract the binary glTF asset from the input b3dm. i3dmToGlb Extract the binary glTF asset from the input i3dm. cmptToGlb Extract the binary glTF assets from the input cmpt. splitCmpt Split the input cmpt and write out its inner tiles. convertB3dmToGlb Convert a b3dm file into a glTF asset that uses glTF extensions to represent the batch- and feature table information convertPntsToGlb Convert a pnts file into a glTF asset that uses glTF extensions to represent the point properties and batch- and feature table information convertI3dmToGlb Convert an i3dm file into a glTF asset that uses glTF extensions to represent the batch- and feature table information. This conversion may be lossy if the GLB of the input i3dm contains animations. optimizeB3dm Pass the input b3dm through gltf-pipeline. To pass options to gltf-pipeline, place them after --options. (--options -h for gltf-pipeline help) optimizeI3dm Pass the input i3dm through gltf-pipeline. To pass options to gltf-pipeline, place them after --options. (--options -h for gltf-pipeline help) updateAlignment Update the alignment of the batch- and feature table and the tile dataas a whole, to meet the alignment requirements of the specification. This can be applied to B3DM, I3DM, PNTS, or CMPT tile data. gzip Gzips the input tileset directory. ungzip Ungzips the input tileset directory. combine Combines all external tilesets into a single tileset.json file. merge Merge any number of tilesets together into a single tileset. mergeJson Merge any number of tilesets together into a single tileset without copying resources to output directory. upgrade Upgrades legacy tilesets to comply to the 3D Tiles specification. By default, this will upgrade legacy tilesets to comply to 3D Tiles 1.0. These upgrades include: - The asset version will be set to '1.0' - Content that uses a 'url' will be upgraded to use 'uri'. - The 'refine' value will be converted to be in all-uppercase. - glTF 1.0 models in B3DM or I3DM will be upgraded to glTF 2.0. When specifying '--targetVersion 1.1', then the upgrades will include: - The asset version will be set to '1.1' - Content that uses a 'url' will be upgraded to use 'uri'. - The 'refine' value will be converted to be in all-uppercase. - The '3DTILES_content_gltf' extension declaration will be removed. - PNTS, B3DM, and I3DM content will be converted to glTF. pipeline Execute a pipeline that is provided as a JSON file analyze Analyze the input file, and write the results to the output directory. This will accept B3DM, I3DM, PNTS, CMPT, and GLB files (both for glTF 1.0 and for glTF 2.0), and write files into the output directory that contain the feature table, batch table, layout information, the GLB, and the JSON of the GLB tilesetToDatabase Create a sqlite database for a tileset. (Deprecated - use 'convert' instead) databaseToTileset Unpack a tileset database to a tileset folder. (Deprecated - use 'convert' instead) createTilesetJson Creates a tileset JSON file that just refers to given tile content files. If the input is a single file, then this will result in a single (root) tile with the input file as its tile content. If the input is a directory, then all content files in this directory will be used as tile content, recursively. The exact set of file types that are considered to be 'tile content' is not specified, but it will include GLB, B3DM, PNTS, I3DM, and CMPT files. Options: --version Show version number [boolean] -h, --help Show help [boolean] -f, --force Output can be overwritten if it already exists. [boolean] [default: false] --logLevel The log level. Valid values are 'trace', 'debug', 'info', 'warn', 'error', 'fatal', and 'silent' [string] [default: "info"] --logJson Whether log messages should be printed as JSON instead of pretty-printing [boolean] [default: false] Unknown arguments: i, o, lasTo3dtiles
最新发布
10-23
USES_CONVERSION 是 ATL(Active Template Library)中的一个宏定义,主要用于支持编码转换操作。在使用该宏时,需要包含特定的头文件,并且需要注意其使用场景以避免潜在的问题。 为了使用 USES_CONVERSION 宏以及相关的字符串转换宏(如 A2W、W2A 等),必须包含以下头文件: ```cpp #include "atlconv.h" ``` 这个头文件提供了必要的定义和宏支持,使得在 ATL 项目中进行 ANSI 和 Unicode 字符串之间的转换成为可能[^1]。 在实际代码中,USES_CONVERSION 的使用通常如下所示: ```cpp #include <atlconv.h> void fn() { while (true) { { USES_CONVERSION; DoSomething(A2W("SomeString")); } } } ``` 通过调用 USES_CONVERSION 宏,可以确保后续的字符串转换宏(如 A2W)能够正常工作[^2]。 然而,在使用 USES_CONVERSION 时需要注意一些事项: 1. **栈空间限制**:ATL 转换宏使用栈作为临时存储空间,直到调用它的函数返回前,这部分内存不会被释放。因此,在频繁调用转换宏的情况下(例如在一个循环体内多次调用),可能会导致栈溢出(stack overflow)。 2. **适用于短字符串**:只适合进行短字符串的转换,因为栈空间是有限的(VC 默认为 2MB)。 3. **避免大文件内容转换**:不要尝试对大型文件内容进行转换,因为这可能导致栈空间耗尽。 4. **替代方案**:对于大量数据或循环体内的转换需求,建议使用 Windows API 函数 MultiByteToWideChar 和 WideCharToMultiByte 进行转换,而不是依赖 ATL 的转换宏[^3]。 如果需要在一个函数中多次进行字符串转换,可以考虑将这些转换操作封装到独立的函数中,这样每次调用都会有一个新的栈空间用于存储转换结果,从而避免栈溢出问题。 总之,虽然 USES_CONVERSION 提供了方便的字符串转换功能,但在使用时仍需谨慎,特别是当涉及到频繁的转换操作或大数据量处理时,应当采取适当的措施来防止潜在的问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值