我正在试图弄清楚C ++ 11规范中是否有任何内容。以下代码(GitHub link here)的预期行为:
#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <tchar.h>
#include <algorithm>
#include <string>
using namespace std;
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 );
int main(int argc, char* argv[]) {
const string path = "E:\\util\\bin\\";
const string procName = "procReal.exe";
const string argToFilter = "-t";
string origValue;
string passedValue;
for(int i = 1; i < argc; i++)
{
origValue.append(" ").append(argv[i]);
}
for(int i = 1; i < argc; i++)
{
if (!caseInsensitiveStringCompare(argv[i],argToFilter))
{
passedValue.append(" ").append(argv[i]);
}
else
{
i++; // skip over argument and it's value
}
}
const LPCTSTR exeModule = (path+procName).c_str();
std::vector<char> chars(passedValue.c_str(), passedValue.c_str() + passedValue.size() + 1u);
LPTSTR exeArgs = &chars[0];
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
GetStartupInfo(&si);
FILE* traceFile;
traceFile = fopen ((path+"lastRun.txt").c_str(), "w"); // This causes exeModule to change value for unknown reasons???
fprintf(traceFile, "orig: %s%s\n", exeModule, origValue.c_str());
fprintf(traceFile, "%s%s\n", exeModule, exeArgs);
SetLastError(0);
// Start the child process.
if( !CreateProcess( exeModule, // use module name with args for exeArgs
exeArgs, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(GetLastError()));
fclose(myfile);
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
DWORD exit_code;
GetExitCodeProcess(pi.hProcess, &exit_code);
fprintf(traceFile, "Exit Code: %d\n", int(exit_code));
fclose(traceFile);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exit_code;
}
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
std::string str1Cpy( str1 );
std::string str2Cpy( str2 );
std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
return ( str1Cpy == str2Cpy );
}
这主要是因为发现这在struct Scalar {
int data;
Scalar(int x) : data(x) {}
int get() {
return data;
}
Scalar &square() {
scale(data);
return *this;
}
void scale(int rhs) {
data *= rhs;
}
};
int main() {
Scalar v(3);
v.square().scale(v.get());
return v.data;
}
和g++
之间做了不同的事情:
clang++
答案似乎应该出现在n3242的§5.2.2和§5.2.5中,但我无法追踪具体内容。
答案 0 :(得分:8)
如果我正确阅读了内容,则代码的行为未指定。 N3337 for C ++ 11引用:
§1.9[intro.execution] / 15
除非另有说明,否则评估各个运营商的操作数 并且个别表达的子表达式没有被排序。 [...] 如果对标量对象的副作用相对于其中任何一个都没有排序 对同一标量对象或值计算的另一个副作用 使用相同标量对象的值,行为未定义。
但随后是
调用函数中的每个评估(包括其他函数 在之前或之后没有特别排序的调用) 被调用函数体的执行是不确定的 关于被叫的执行顺序排序 功能 9
9)换句话说,函数执行不会与每个函数交错 其他
和
§5.2.2[expr.call] / 8
[注意:后缀表达式和。的评估 参数表达式相对于彼此都是无序的。所有 参数表达式评估的副作用在之前排序 输入功能(见1.9)。 -end note ]
因此,您对Scalar::data
的修改和无关读取是不确定的。
话虽如此,它可能会在C ++ 1z中改变并定义明确:
N4606§5.2.2[expr.call] / 5
postfix-expression 在每个表达式之前排序 表达式列表和任何默认参数。一个初始化 参数,包括每个相关的值计算和边 效果,相对于任何其他的不确定地排序 参数。
因此,在C ++ 1z中,v.data
应该等于81(如果我正确读取了内容)