我目前正在审查一个非常古老的C++项目,并在那里看到许多代码重复.
例如,有一个包含5个MFC消息处理程序的类,每个消息处理程序包含10行相同的代码.或者,每个地方都有一个5行代码段用于非常具体的字符串转换.在这些情况下,减少代码重复不是问题.
但我有一种奇怪的感觉,我可能会误解某些东西,并且最初有这种重复的原因.
什么可能是重复代码的正当理由?
C++允许超载operator new-全局和每个类-通常operator new,operator new[]所使用new[]的语句和位置operator new分开.
这三个中的前两个通常因使用自定义分配器和添加跟踪而过载.但是放置operator new似乎非常简单 - 它实际上什么也没做.例如,在Visual C++中,默认实现只返回传递给调用的地址:
//from new.h
inline void* operator new( size_t, void* where )
{
return where;
}
Run Code Online (Sandbox Code Playgroud)
它还能做什么?为什么以及如何明智地超载放置operator new?
在C++中,有时会定义一个变量,但不会使用.这是一个示例 - 与COM_INTERFACE_ENTRY_FUNC_BLINDATL宏一起使用的函数:
HRESULT WINAPI blindQuery( void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/ )
{
DEBUG_LOG( __FUNCTION__ ); //DEBUG_LOG macro expands to an empty string in non-debug
DEBUG_LOG( iid );
iid; // <<<<<<<----silence compiler warning
if( ppv == 0 ) {
return E_POINTER;
}
*ppv = 0;
return E_NOINTERFACE;
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,iid参数与DEBUG_LOG宏一起使用,在非调试配置中扩展为空字符串.因此,iid不能选择在签名中注释或删除变量名称.当编译非调试配置时,编译器会产生C4100: 'iid' : unreferenced formal parameter警告,因此为了使警告静音iid;,添加了被认为是无操作的语句.
问题如下:如果我们有以下任何声明:
CSomeType variableName; //or
CSomeType& variableName; //or
CSomeType* variableName;
Run Code Online (Sandbox Code Playgroud)
将在C++代码中的以下语句:
variableName; …Run Code Online (Sandbox Code Playgroud) 我有一堆代码,std::string比较类型的对象与字符串文字的相等性.像这样的东西:
//const std:string someString = //blahblahblah;
if( someString == "(" ) {
//do something
} else if( someString == ")" ) {
//do something else
} else if// this chain can be very long
Run Code Online (Sandbox Code Playgroud)
比较时间累积到一个严重的数量(是的,我描述),所以加快它是很好的.
代码将字符串与众多短字符串文字进行比较,这种比较很难避免.保留声明的字符串std::string很可能是不可避免的 - 有数千行代码.离开字符串文字和比较==也可能是不可避免的 - 重写整个代码将是一个痛苦.
问题是Visual C++ 11附带的STL实现使用了一些奇怪的方法.==映射到std::operator==(const basic_string&, const char*)哪些调用basic_string::compare( const char* ),这些调用又调用std::char_traits<char>( const char* )哪些调用strlen()来计算字符串文字的长度.然后对两个字符串运行比较,并将两个字符串的长度传递给该比较.
编译器很难分析所有这些并发出遍历字符串文字两次的代码.使用短文字,时间不多,但每次比较都涉及遍历文字两次而不是一次.简单地打电话strcmp()很可能会更快.
有没有什么我可以做的,比如编写一个自定义比较器类,有助于避免在这种情况下两次遍历字符串文字?
在C++中,可以声明堆栈分配的对象const:
const Class object;
Run Code Online (Sandbox Code Playgroud)
之后尝试在这样的对象上调用非const方法是未定义的行为:
const_cast<Class*>( &object )->NonConstMethod(); //UB
Run Code Online (Sandbox Code Playgroud)
堆分配的对象可以const具有相同的后果吗?我的意思是有可能是以下几点:
const Class* object = new Class();
const_cast<Class*>( object )->NonConstMethod(); // can this be UB?
Run Code Online (Sandbox Code Playgroud)
还是未定义的行为?
受到关于SQLite3中以下代码的这个问题的启发:
static int strlen30(const char *z){
const char *z2 = z;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
Run Code Online (Sandbox Code Playgroud)
这附带一条提交消息,说这个函数有助于int溢出.
我对这部分特别感兴趣:
const char *z2 = z;
while( *z2 ){ z2++; }
Run Code Online (Sandbox Code Playgroud)
对我来说,这个循环前进,z2直到z2指向null终止符.然后z2-z产生字符串长度.
为什么不使用strlen()这个部分并重写如下:
return 0x3fffffff & (int)(strlen(z));
Run Code Online (Sandbox Code Playgroud)
为什么使用循环+减法代替strlen()?什么可以循环+减法做什么strlen()不可以?
我有这个ActionFilter
public class AppOfflineFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.ActionName != "AppOffLine" &&
filterContext.HttpContext.Request.UserHostName != "127.0.0.1")
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new { action = "AppOffLine", Controller = "Home" }));
}
}
}
Run Code Online (Sandbox Code Playgroud)
它从起始页面起作用,它不在一个区域下,它不能在一个区域工作,因为它将重定向到/ Area/Home/Appoffline而不是/ Home/AppOffline
可以修复吗?
还有一种方法可以确定哪个控制器/动作重定向到使用泛型和强类型代码?
我有一个有效的.NET MVC应用程序,但是当在Windows 8上使用IE10访问时,浏览器源代码显示所有动态生成的URL,例如.与Url.Action("Index", "Home")写成:
/(F(usb6gVWyFnXevozQyFvVxVdbsN0uM9kZ5wNu9gT9pWBINGuodOdzLKkIQzfhqy3UhnCLyXf78LugXZO2UPYfMbNzSJJawmbqUBL56TjKpXgWpiMdVAjB1T3YcPlGhZePwFd6C9P_f_Y89KiDnWcA9EfR1m0ud3IcBYTW8OwZxOMTd8bxt5hM8mgXVN6OSdoo3IMwRA2))/ 首页/索引
代替:
/首页/索引
如果我们用静态HTML编写链接:
<a href="/Home/Index">[linktext]</a>
Run Code Online (Sandbox Code Playgroud)
IE10重定向到登录页面.问题是暂时离开站点以转到具有返回第一个站点的链接的合作伙伴站点.由于注入的代码丢失,返回URL不再有效并重定向到登录.
任何人都知道为什么要注入此代码(Framework或IE10问题?)
为什么Vector(ArrayList for Java people)的经典实现在每次扩展时将其内部数组大小加倍,而不是将其增加三倍或四倍?
我使用以下代码在我的视图中获取当前的"操作",因为我想基于它自定义构建actionlink.
ViewContext.RequestContext.RouteData.Values("action")
Run Code Online (Sandbox Code Playgroud)
我的最终目标是使用Javascript构建一些动作链接,并且.js需要知道当前控制器和动作是什么,因为我希望它具有灵活性.我通过浏览框架找到了上述内容,但我不知道我是否找到了正确的东西.
即
var routeData = ViewContext.RequestContext.RouteData;
var linkStub = '/@routeData.Values("controller")/@routeData.Values("action")';
Run Code Online (Sandbox Code Playgroud)
有谁知道这是最简单/最直接的方法吗?
c++ ×6
string ×2
visual-c++ ×2
algorithm ×1
arraylist ×1
asp.net-mvc ×1
c ×1
const ×1
performance ×1
razor ×1
sqlite ×1
stl ×1
strlen ×1
vector ×1