首先,你可能知道const
可以用来制作一个对象的数据或一个不可修改的指针或两者兼而有之.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Run Code Online (Sandbox Code Playgroud)
但是您也可以使用以下语法:
Object const *obj; // same as const Object* obj;
Run Code Online (Sandbox Code Playgroud)
唯一重要的是你把const
关键字放在星号的哪一边.我个人更喜欢把const
上式的左边指定它的数据是不可修改的,因为我觉得它读取我的左到右的心态更好,但其语法是先?
更重要的是,为什么有两种正确的const
数据指定方式,如果有的话,你会更喜欢或需要哪种方式?
编辑:
所以听起来这是一个武断的决定,因为编译器应该如何解释事物的标准早在我出生之前起草了.因为const
应用于关键字左侧的内容(默认情况下?)我猜他们认为添加"快捷方式"以应用关键字并以其他方式输入限定符至少直到声明更改为止时没有任何损害解析*或&...
这是C的情况,然后我假设?
这是从垃圾收集线程中衍生出来的,我认为这是一个简单的答案,它产生了很多关于某些特定智能指针实现的评论,所以看起来值得开始一篇新帖子.
最终问题是C++中智能指针的各种实现是什么,它们如何比较?只是简单的利弊或异常,并找到你可能认为应该工作的东西.
我已经发布了一些我已经使用过或者至少掩饰过的实现,并考虑使用下面的答案,并且我对它们的差异和相似性的理解可能不是100%准确所以请随意根据需要检查或纠正我.
目标是了解一些新的对象和库,或者纠正我对已经广泛使用的现有实现的使用和理解,并最终为其他人提供合适的参考.
好的作为前言我需要缓存很少修改数据的相对较小的子集,以避免出于性能原因频繁查询数据库.这些数据大量用于只读意义,因为它通常由其他表中的更大数据集引用.
我编写了一个类,它能够在内存中基本上存储所讨论的两个表的全部内容,同时监听提交更改以及用于更新缓存对象的线程安全回调机制.
我当前的实现有两个std::vectors
用于每个表的元素.该类提供两个访问每个矢量的整体以及方便的方法用于搜索通过表数据的特定元素std::find
,std::find_if
等.
有谁知道,如果使用std::list
,std::set
或者std::map
在std::vector
用于搜索将是可取的?大多数情况下,在建立新连接后从数据库填充一次后将要求这些容器.
我也愿意使用VS2010或Boost支持的C++ 0x功能.
谈到这一点,我是新手.任何人都可以提供以下内存障碍之间差异的简化解释吗?
MemoryBarrier();
_mm_mfence();
asm volatile ("" : : : "memory");
_ReadWriteBarrier();
如果没有一个简单的解释,一些链接到好文章或书籍可能会帮助我顺利完成.到目前为止,我只是使用其他包装这些调用所写的对象,但我希望能够比我目前的想法有更好的理解,这基本上就是有不止一种方法来实现内存障碍.
我希望能够在记录时通过简单的id识别线程,以便很容易跟踪单个线程的执行.使用API的Windows GetCurrentThreadId()
可以实现我想要的.在boost::thread
有一个方法get_id()
但这不代表整数的整数值.这个对象有一个thread_data成员,它包含一个似乎是我想要的id,但数据成员是私有的,所以无法访问.
为显示或识别目的访问线程ID的提升方式是什么?
我正在更新一些旧代码,以使用C++ 11功能代替boost等价物.然而,并非所有东西都是简单的命名空间替换,如无序容器和智能指针.
例如boost::function
有方法empty()
,clear()
但std::function
没有.
有一个已operator()
定义的std::function
,我一直在使用替换empty()
引用,但我应该用什么来替换clear()
引用?
我已经考虑过使用std::function
赋值运算符并指定nullptr
清除它,但我担心可能会产生无意识的副作用,不仅清除底层函数,还会使对象无法使用.
显然,更好的解决方案是任何可重用的成员函数对象的默认初始化,这种方式总是有一个有效的回调,可以简单地用用户提供的回调更新,但我只是想直接替换以前的用法而不是代码审查.
我有一个应用程序,它从数据库中加载一些blob数据,可以表示各种位图和图标的png格式或原始二进制数据.这是存储在std::vector<unsigned char>
我正在使用CImageList
对象在树视图,工具栏图像等中显示各种图像,但问题是从内存中的数据创建位图会变得模糊,好像它在执行如下操作时缺少像素:
std::vector<unsigned char> bits;
HBITMAP hbitmap = CreateBitmap(16, 16, 1, 32, bits.data());
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我现在只需将向量中的data()写入临时文件,然后使用LoadImage将其读回并从中创建HBITMAP.这是完美的,但无可否认,这是一个无耻的黑客,我希望完全没必要.
我在网上环顾四周,但没有找到任何关于如何"正确"从内存创建hbitmaps的好例子.我希望能够创建这些位图,以便添加到图像列表中,而无需任何文件i/o和有限数量的复制数据(如果可能).
寻找最好的方法来做到这一点,显然Windows特定的代码是好的.
更新:
根据jdv的回答,我开始使用CreateCompatibleBitmap,CreateDIBitmap,最后是CreateDIBSection.所有这些最终创建了可爱的黑色位图,而不是之前的模糊位图,所以我必须再次做错了我的猜测是因为这个位图创建是在一个没有屏幕直流或窗口概念的对象中完成的,使用GetDC(NULL)
和CreateCompatibleDC(NULL)
不好.示例代码:
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biHeight = 16;
bmi.bmiHeader.biWidth = 16;
bmi.bmiHeader.biPlanes = 1;
HDC dc = CreateCompatibleDC(NULL);
HBITMAP hbitmap = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, (void**)blobData.GetMember<FILEDATAFIELD_DATA>().data(), NULL, 0);
Run Code Online (Sandbox Code Playgroud)
我现在当然认为必须有一个更简单的方法来解决这个问题,或许完全避免使用HBITMAP并直接与CBitmap
班级合作?当它归结为将图像添加到CImageList
我正在使用CBitmap::FromHandle(HBITMAP hbitmap, COLORREF mask)
的时候.有谁知道CBitmap
从一个初始化对象的简单方法std::vector<unsigned char>
?
好吧,所以开始这是严格的Windows,我更喜欢使用C++而不是.NET,但我不反对,boost::filesystem
虽然如果可以避免支持直接的Windows API我更喜欢.
现在,该场景是另一台机器上的应用程序,我无法更改将在机器上的特定目录中创建文件,我需要备份并执行一些额外的处理.目前我已经制作了一个小应用程序,它将使用FindFirstChangeNotification
和FindNextChangeNotification
Windows API 在目标目录中查找和监听更改通知.
问题是,虽然我可以在目录中创建新文件,修改,大小更改等时收到通知,但它只通知一次,并没有具体告诉我哪些文件.我也看了一下ReadDirectoryChangesW
,但除了我可以获得更具体的信息外,它的故事也是如此.
现在我可以扫描目录并尝试获取锁定或打开文件以确定上次通知中的具体更改以及它们是否可供进一步使用但是在复制大文件的情况下我发现这不是很好足够的文件将无法被操作,我不会在第一次之后得到任何其他通知,所以没有办法告诉它何时实际完成复制,除非在第一次通知后我不断尝试获取锁,直到它成功.
我能想到的另一件事就是不那么强硬就是拥有某种终结令牌文件,但由于我无法控制创建文件的应用程序,所以我不知道我是怎么做的要做到这一点,它仍然不理想.
有什么建议?
我假设这是不可能的,因为我收到以下错误:
error C3533: 'auto': a parameter cannot have a type that contains 'auto'
Run Code Online (Sandbox Code Playgroud)
这是重现错误的代码片段:
int myInts[] = {1,2,3,3,3,4};
std::vector<int> myVec(myInts, myInts + sizeof(myInts)/sizeof(int));
myVec.erase(
std::remove_if(myVec.begin(), myVec.end(),
[](auto i){return i==3;}), // lambda param error
myVec.end());
Run Code Online (Sandbox Code Playgroud)
现在如果你要写这个而不是一切都很好,它会擦除值为3的元素:
int myInts[] = {1,2,3,3,3,4};
std::vector<int> myVec(myInts, myInts + sizeof(myInts)/sizeof(int));
myVec.erase(
std::remove_if(myVec.begin(), myVec.end(),
[](int i){return i==3;}),
myVec.end());
Run Code Online (Sandbox Code Playgroud)
那么你可以简单地不用auto
作函数参数,因为错误暗示了吗?
这是因为类型auto
是由rvalue决定的,编译器无法推断它尽管它是在已知向量上执行的算法的谓词int
?
有谁知道原因?
是否可以在本地匿名函数中使用周围模板函数的模板类型参数?我很确定我不能声明模板lambda ...
例如,我将如何做这样的事情:
template <typename T>
void TrimString(std::basic_string<T>& str, const std::locale& loc = std::locale())
{
// std::isspace as lambda unary predicate?
auto fn = [&loc](T c){ return std::use_facet<std::ctype<T>>(loc).is(std::ctype_base::space, c); };
// trim right
str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(fn)).base(), str.end());
// trim left
str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(fn)));
}
Run Code Online (Sandbox Code Playgroud)
目前,这会产生以下错误:
error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为lambda T
对周围模板函数的参数没有任何线索.
我使用VS2010和gcc 4.7,但我不想使用boost.
有任何想法吗?
编辑:我认为问题是模板参数本身似乎是错误的.而是使用std::not1
lambda函数编译.这是更详细的错误输出:
error C2039: 'argument_type' : is not a member of '`anonymous-namespace'::<lambda0>'
: see declaration of …
Run Code Online (Sandbox Code Playgroud) CWnd
通过多重继承在一些MFC 派生对象上使用纯虚拟接口,我收到了一些警告.我相信这是由定义需要为消息映射实现的方法引起的.
warning C4407: cast between different pointer to member representations, compiler may generate incorrect code
Run Code Online (Sandbox Code Playgroud)
这听起来不仅仅是一个警告,更像是可能导致堆损坏的事情.那么是否有另一种方法可以执行类似于下面的操作,这不会导致MFC动态向下转换宏比平时更多?
class ISomeInterface
{
public:
virtual LRESULT OnSomeRegisteredMessage(WPARAM wp, LPARAM lp) = 0;
};
class CSomeCoolWnd : public CWnd, public ISomeInterface
{
public:
LRESULT OnSomeRegisteredMessage(WPARAM wp, LPARAM lp);
};
BEGIN_MESSAGE_MAP(CSomeCoolWnd , CWnd)
ON_REGISTERED_MESSAGE(WM_USER_DEFINED, &CSomeCoolWnd::OnSomeRegisteredMessage)
END_MESSAGE_MAP()
Run Code Online (Sandbox Code Playgroud)
我唯一想到的就是从界面中注释出消息处理程序,并留下评论告诉消费者他们应该实现它们.但是,通过编译器错误强制执行该操作会很好,而不是让它们使用接口并在运行时从丢失的内容中获得意外结果.
这是一个完整性检查,因为我失去了我的.
我有一个方法IsCaptured()
,它将枚举状态成员与给定值进行比较并返回一个bool
.我结合使用鼠标阈值检查来确定是否应该发送拖动开始消息并开始拖动操作.问题是当它不应该被鼠标移动时触发.我添加了跟踪消息,如下所示:
TRACE(L"%s\n", (IsCaptured()) ? L"true" : L"false");
CPoint delta = pt - m_trackMouse;
static CPoint thresh(GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
if (IsCaptured() &&
abs(delta.x) >= thresh.x || abs(delta.y) >= thresh.y)
{
TRACE(L"%s\n", (IsCaptured()) ? L"true" : L"false");
// Send message to enter drag mode
bool bDrag = ::SendMessage(m_trackWnd, WM_DD_BEGIN, ::GetDlgCtrlID(m_trackWnd), (LPARAM)(void*)&m_info) != 0;
// ...
}
Run Code Online (Sandbox Code Playgroud)
现在奇怪的部分,输出:
false
false
Run Code Online (Sandbox Code Playgroud)
该方法是这样实现的,并m_dragState
设置为NONE
截获按下按钮:
enum { NONE, CAPTURED, DRAGGING };
bool IsCaptured() const { return m_dragState == CAPTURED; …
Run Code Online (Sandbox Code Playgroud) c++ ×12
c++11 ×3
mfc ×3
stl ×3
boost ×2
lambda ×2
windows ×2
bitmap ×1
c ×1
c++-faq ×1
const ×1
debugging ×1
file ×1
filesystems ×1
find ×1
gdi ×1
hbitmap ×1
if-statement ×1
optimization ×1
std-function ×1
syntax ×1
templates ×1
visual-c++ ×1