关于std::copy 中的overlapped问题解释

转自 http://www.trilithium.com/johan/2006/02/copy-confusion/ 

 

The standard C++ library contains std::copy which is the generic equivalent to the Cmemcpy function. There's nothing stopping you from using std::memcpy in C++ as well – but why would you do that when there's a replacement that's capable of working with all kinds of iterators while being just as efficient as memcpy for built-in types?

Indeed, once you start std::copying there should be no need to look back. However, if you're familiar with memcpy you must also be aware that it cannot be used if the source and destination memory areas overlap. Let's take a look at the std::copy description to see if it has a similar limitation:

template <class InIt, class OutIt>

OutIt copy(InIt first, InIt last, OutIt result);

  • Effects: Copies elements in the range [first, last) into the range [result, result + (last - first)) starting from first and proceeding to last.
  • Returns: result + (last - first)
  • Requires: result shall not be in the range [first, last).
  • Complexity: Exactly last - first assignments.

Aha! That requirement could certainly prove to be a problem when we're copying overlapping ranges. In C we're supposed to use the memmove function if the source and destination overlap. Surely C++ must offer us something for when std::copy can't do the job? Yes, of course it does:

template <class BidIt1, class BidIt2>

BidIt2 copy_backward(BidIt1 first, BidIt1 last, BidIt2 result);

  • Effects: Copies elements in the range [first, last) into the range [result - (last - first), result) starting from last - 1 and proceeding to first.
  • Returns: result - (last - first)
  • Requires: result shall not be in the range [first, last).
  • Complexity: Exactly last - first assignments.

Hey, std::copy_backward has the exact same requirement of result not being in the source range! How am I supposed to copy overlapping ranges? Where is my genericmemmove?

It's easy, especially for a someone with a strong C background looking for memmove, to draw the wrong conclusion from the iterator requirements. Read the descriptions again carefully. Nothing is said about overlapping ranges, only that result can't be in the source range. When there is overlap at the start of the source range, std::copy will work fine:

 

True to its name, std::copy_backward will copy backwards, so result actually marks the end of the region when you call this function. That covers the case where overlap occurs at the end of the source range:

 

 

Both std::copy and std::copy_backward can in fact deal with overlap, you just have to call the correct one depending on the situation. Typically you don't even need to compare iterators to determine which function to call because you already know what kind of overlap you have at the call site.

There is no std::move that does the right thing automatically. Such a function could be written, but it would be less general as well as less efficient than the two existing copy functions; it would have to compare destination and source range iterators every time.

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
重叠IO模型之OverLapped完成例程模型WSACompletionRoutineServer VS2010 基础入门 客户端与服务器端 客户端向服务器端发送数据 可接收多个客户端 #include #include #pragma comment (lib, "ws2_32.lib") #define PORT 8088 #define MSG_SIZE 1024 SOCKET g_sConnect; bool g_bConnect = false; typedef struct { WSAOVERLAPPED overLap; WSABUF wsaBuf; char chMsg[MSG_SIZE]; DWORD nRecvNum; DWORD nFlags; SOCKET sClient; }PRE_IO_OPERATION_DATA, *LP_PER_IO_OPERATION_DATA; void CALLBACK CompletionRoutine(DWORD dwError, DWORD dwTrans, LPWSAOVERLAPPED lpOverlap, DWORD nFlags); DWORD WINAPI workThread(LPVOID lp) { LP_PER_IO_OPERATION_DATA lpData; while(TRUE) { if (g_bConnect) // 有新的连接 { // 为lpData分配空间并初始化 lpData = (LP_PER_IO_OPERATION_DATA)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PRE_IO_OPERATION_DATA)); lpData->wsaBuf.len = MSG_SIZE; lpData->wsaBuf.buf = lpData->chMsg; lpData->sClient = g_sConnect; WSARecv(lpData->sClient, &lpData->wsaBuf, 1, &lpData->nRecvNum, &lpData->nFlags, &lpData->overLap, CompletionRoutine); g_bConnect = false; // 处理完毕 } SleepEx(1000, TRUE); } return 0; } // 系统在WSARecv收到信息后,自动调用此函数,并传入参数--回调函数 void CALLBACK CompletionRoutine(DWORD dwError, DWORD dwTrans, LPWSAOVERLAPPED lpOverlap, DWORD nFlags) { LP_PER_IO_OPERATION_DATA lpData = (LP_PER_IO_OPERATION_DATA)lpOverlap; if (0 != dwError) // 接收失败 { printf("Socket %d Close!\n", lpData->sClient); closesocket(lpData->sClient); HeapFree(GetProcessHeap(), 0, lpData); } else // 接收成功 { lpData->chMsg[dwTrans] = '\0'; send(lpData->sClient, lpData->chMsg, dwTrans, 0); printf("Socket:%d MSG: %s \n", lpData->sClient, lpData->chMsg); memset(&lpData->overLap, 0, sizeof(WSAOVERLAPPED)); lpData->wsaBuf.len = MSG_SIZE; lpData->wsaBuf.buf = lpData->chMsg; // 继续接收来自客户端的数据 实现 WSARecv与CompletionRoutine循环 WSARecv(lpData->sClient, &lpData->wsaBuf,1, &lpData->nRecvNum, &lpData->nFlags, &lpData->overLap, CompletionRoutine); } } int main() { WSADATA wsaData; WSAStartup(0x0202, &wsaData); SOCKET sListen; sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in addrListen; addrListen.sin_family = AF_INET; addrListen.sin_port = htons(PORT); addrListen.sin_addr.S_un.S_addr = htonl(ADDR_ANY); int nErrorCode = 0; nErrorCode = bind(sListen, (sockaddr*)&addrListen, sizeof(sockaddr)); nErrorCode = listen(sListen, 5); DWORD nThreadID; CreateThread(NULL, 0, workThread, NULL, 0, &nThreadID); sockaddr_in addrConnect; int nAddrLen = sizeof(sockaddr_in); printf("Server Started!\n"); while(TRUE) { g_sConnect= accept(sListen, (sockaddr*)&addrConnect, &nAddrLen); if (INVALID_SOCKET == g_sConnect) { return -1; } g_bConnect = true; // 连接成功 printf("Accept Client :%s -- PORT:%d\n", inet_ntoa(addrConnect.sin_addr), htons(addrConnect.sin_port)); } return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值